Setting inferred volatile on symbol affected by address-of (struct Person*~) main::$0 ← & (struct Person) main::jesper Setting inferred volatile on symbol affected by address-of (struct Person*~) main::$2 ← & (struct Person) main::henriette Created struct value member variable (byte) main::jesper_id Created struct value member variable (byte[$10]) main::jesper_name Converted struct value to member variables (struct Person) main::jesper Created struct value member variable (byte) main::henriette_id Created struct value member variable (byte[$10]) main::henriette_name Converted struct value to member variables (struct Person) main::henriette Adding struct value list initializer (byte) main::jesper_id ← (number) 4 Adding struct value list initializer (byte[$10]) main::jesper_name ← (string) "jesper" Adding struct value list initializer (byte) main::henriette_id ← (number) 7 Adding struct value list initializer (byte[$10]) main::henriette_name ← (string) "henriette" Rewriting struct pointer member access *((struct Person*) print_person::person).id Rewriting struct pointer member access *((struct Person*) print_person::person).name Rewriting struct pointer member access *((struct Person*) print_person::person).name Warning! Adding boolean cast to non-boolean condition *(*((byte[$10]*) print_person::$1) + (byte) print_person::i) Culled Empty Block (label) print_person::@4 Culled Empty Block (label) print_person::@5 Culled Empty Block (label) print_person::@6 Adding versioned struct unwinding for (struct Person) main::jesper#0 Adding versioned struct unwinding for (struct Person) main::henriette#0 CONTROL FLOW GRAPH SSA @begin: scope:[] from to:@1 main: scope:[main] from @2 (byte) idx#18 ← phi( @2/(byte) idx#20 ) (byte) main::jesper_id#0 ← (number) 4 (byte[$10]) main::jesper_name#0 ← (const string) main::$4 (struct Person) main::jesper#0 ← struct-unwound {(byte) main::jesper_id#0, (byte[$10]) main::jesper_name#0} (struct Person*~) main::$0 ← & (struct Person) main::jesper#0 (struct Person*) print_person::person#0 ← (struct Person*~) main::$0 call print_person to:main::@1 main::@1: scope:[main] from main (byte) idx#10 ← phi( main/(byte) idx#8 ) (byte) idx#0 ← (byte) idx#10 (byte) main::henriette_id#0 ← (number) 7 (byte[$10]) main::henriette_name#0 ← (const string) main::$5 (struct Person) main::henriette#0 ← struct-unwound {(byte) main::henriette_id#0, (byte[$10]) main::henriette_name#0} (struct Person*~) main::$2 ← & (struct Person) main::henriette#0 (struct Person*) print_person::person#1 ← (struct Person*~) main::$2 call print_person to:main::@2 main::@2: scope:[main] from main::@1 (byte) idx#11 ← phi( main::@1/(byte) idx#8 ) (byte) idx#1 ← (byte) idx#11 to:main::@return main::@return: scope:[main] from main::@2 (byte) idx#12 ← phi( main::@2/(byte) idx#1 ) (byte) idx#2 ← (byte) idx#12 return to:@return @1: scope:[] from @begin (byte*) SCREEN#0 ← ((byte*)) (number) $400 (byte) idx#3 ← (number) 0 (byte[]) DIGIT#0 ← (const string) $0 to:@2 print_person: scope:[print_person] from main main::@1 (byte) idx#13 ← phi( main/(byte) idx#18 main::@1/(byte) idx#0 ) (struct Person*) print_person::person#2 ← phi( main/(struct Person*) print_person::person#0 main::@1/(struct Person*) print_person::person#1 ) (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID *((byte*) SCREEN#0 + (byte) idx#13) ← *((byte[]) DIGIT#0 + *((byte*) print_person::$0)) (byte) idx#4 ← ++ (byte) idx#13 *((byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' (byte) idx#5 ← ++ (byte) idx#4 (byte) print_person::i#0 ← (number) 0 to:print_person::@1 print_person::@1: scope:[print_person] from print_person print_person::@2 (byte) idx#19 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 ) (byte) print_person::i#2 ← phi( print_person/(byte) print_person::i#0 print_person::@2/(byte) print_person::i#1 ) (struct Person*) print_person::person#3 ← phi( print_person/(struct Person*) print_person::person#2 print_person::@2/(struct Person*) print_person::person#4 ) (byte[$10]*) print_person::$1 ← (byte[$10]*)(struct Person*) print_person::person#3 + (const byte) OFFSET_STRUCT_PERSON_NAME (bool~) print_person::$3 ← (number) 0 != *(*((byte[$10]*) print_person::$1) + (byte) print_person::i#2) if((bool~) print_person::$3) goto print_person::@2 to:print_person::@3 print_person::@2: scope:[print_person] from print_person::@1 (byte) idx#14 ← phi( print_person::@1/(byte) idx#19 ) (byte) print_person::i#3 ← phi( print_person::@1/(byte) print_person::i#2 ) (struct Person*) print_person::person#4 ← phi( print_person::@1/(struct Person*) print_person::person#3 ) (byte[$10]*) print_person::$2 ← (byte[$10]*)(struct Person*) print_person::person#4 + (const byte) OFFSET_STRUCT_PERSON_NAME *((byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*) print_person::$2) + (byte) print_person::i#3) (byte) idx#6 ← ++ (byte) idx#14 (byte) print_person::i#1 ← ++ (byte) print_person::i#3 to:print_person::@1 print_person::@3: scope:[print_person] from print_person::@1 (byte) idx#15 ← phi( print_person::@1/(byte) idx#19 ) *((byte*) SCREEN#0 + (byte) idx#15) ← (byte) ' ' (byte) idx#7 ← ++ (byte) idx#15 to:print_person::@return print_person::@return: scope:[print_person] from print_person::@3 (byte) idx#16 ← phi( print_person::@3/(byte) idx#7 ) (byte) idx#8 ← (byte) idx#16 return to:@return @2: scope:[] from @1 (byte) idx#20 ← phi( @1/(byte) idx#3 ) call main to:@3 @3: scope:[] from @2 (byte) idx#17 ← phi( @2/(byte) idx#2 ) (byte) idx#9 ← (byte) idx#17 to:@end @end: scope:[] from @3 SYMBOL TABLE SSA (const string) $0 = (string) "0123456789" (label) @1 (label) @2 (label) @3 (label) @begin (label) @end (byte[]) DIGIT (byte[]) DIGIT#0 (const byte) OFFSET_STRUCT_PERSON_ID = (byte) 0 (const byte) OFFSET_STRUCT_PERSON_NAME = (byte) 1 (byte) Person::id (byte[$10]) Person::name (byte*) SCREEN (byte*) SCREEN#0 (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#15 (byte) idx#16 (byte) idx#17 (byte) idx#18 (byte) idx#19 (byte) idx#2 (byte) idx#20 (byte) idx#3 (byte) idx#4 (byte) idx#5 (byte) idx#6 (byte) idx#7 (byte) idx#8 (byte) idx#9 (void()) main() (struct Person*~) main::$0 (struct Person*~) main::$2 (const string) main::$4 = (string) "jesper" (const string) main::$5 = (string) "henriette" (label) main::@1 (label) main::@2 (label) main::@return (struct Person) main::henriette (struct Person) main::henriette#0 (byte) main::henriette_id (byte) main::henriette_id#0 (byte[$10]) main::henriette_name (byte[$10]) main::henriette_name#0 (struct Person) main::jesper (struct Person) main::jesper#0 (byte) main::jesper_id (byte) main::jesper_id#0 (byte[$10]) main::jesper_name (byte[$10]) main::jesper_name#0 (void()) print_person((struct Person*) print_person::person) (byte*) print_person::$0 (byte[$10]*) print_person::$1 (byte[$10]*) print_person::$2 (bool~) print_person::$3 (label) print_person::@1 (label) print_person::@2 (label) print_person::@3 (label) print_person::@return (byte) print_person::i (byte) print_person::i#0 (byte) print_person::i#1 (byte) print_person::i#2 (byte) print_person::i#3 (struct Person*) print_person::person (struct Person*) print_person::person#0 (struct Person*) print_person::person#1 (struct Person*) print_person::person#2 (struct Person*) print_person::person#3 (struct Person*) print_person::person#4 Adding number conversion cast (unumber) 4 in (byte) main::jesper_id#0 ← (number) 4 Adding number conversion cast (unumber) 7 in (byte) main::henriette_id#0 ← (number) 7 Adding number conversion cast (unumber) 0 in (byte) idx#3 ← (number) 0 Adding number conversion cast (unumber) 0 in (byte) print_person::i#0 ← (number) 0 Adding number conversion cast (unumber) 0 in (bool~) print_person::$3 ← (number) 0 != *(*((byte[$10]*) print_person::$1) + (byte) print_person::i#2) Successful SSA optimization PassNAddNumberTypeConversions Inlining cast (byte) main::jesper_id#0 ← (unumber)(number) 4 Inlining cast (byte) main::henriette_id#0 ← (unumber)(number) 7 Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 Inlining cast (byte) idx#3 ← (unumber)(number) 0 Inlining cast (byte) print_person::i#0 ← (unumber)(number) 0 Successful SSA optimization Pass2InlineCast Simplifying constant integer cast 4 Simplifying constant integer cast 7 Simplifying constant pointer cast (byte*) 1024 Simplifying constant integer cast 0 Simplifying constant integer cast 0 Simplifying constant integer cast 0 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) 4 Finalized unsigned number type (byte) 7 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Successful SSA optimization PassNFinalizeNumberTypeConversions Alias (struct Person*) print_person::person#0 = (struct Person*~) main::$0 Alias (byte) idx#0 = (byte) idx#10 Alias (struct Person*) print_person::person#1 = (struct Person*~) main::$2 Alias (byte) idx#1 = (byte) idx#11 (byte) idx#12 (byte) idx#2 Alias (struct Person*) print_person::person#3 = (struct Person*) print_person::person#4 Alias (byte) print_person::i#2 = (byte) print_person::i#3 Alias (byte) idx#14 = (byte) idx#19 (byte) idx#15 Alias (byte) idx#16 = (byte) idx#7 (byte) idx#8 Alias (byte) idx#20 = (byte) idx#3 Alias (byte) idx#17 = (byte) idx#9 Successful SSA optimization Pass2AliasElimination Identical Phi Values (byte) idx#18 (byte) idx#20 Identical Phi Values (byte) idx#0 (byte) idx#16 Identical Phi Values (byte) idx#1 (byte) idx#16 Identical Phi Values (struct Person*) print_person::person#3 (struct Person*) print_person::person#2 Identical Phi Values (byte) idx#17 (byte) idx#1 Successful SSA optimization Pass2IdenticalPhiElimination Simple Condition (bool~) print_person::$3 [33] if((byte) 0!=*(*((byte[$10]*) print_person::$1) + (byte) print_person::i#2)) goto print_person::@2 Successful SSA optimization Pass2ConditionalJumpSimplification Rewriting struct address-of to first member [4] (struct Person*) print_person::person#0 ← (struct Person*)&(byte) main::jesper_id#0 Rewriting struct address-of to first member [12] (struct Person*) print_person::person#1 ← (struct Person*)&(byte) main::henriette_id#0 Successful SSA optimization PassNStructAddressOfRewriting Constant right-side identified [4] (struct Person*) print_person::person#0 ← (struct Person*)&(byte) main::jesper_id#0 Constant right-side identified [12] (struct Person*) print_person::person#1 ← (struct Person*)&(byte) main::henriette_id#0 Successful SSA optimization Pass2ConstantRValueConsolidation Constant (const struct Person*) print_person::person#0 = (struct Person*)&main::jesper_id#0 Constant (const struct Person*) print_person::person#1 = (struct Person*)&main::henriette_id#0 Constant (const byte*) SCREEN#0 = (byte*) 1024 Constant (const byte) idx#20 = 0 Constant (const byte[]) DIGIT#0 = $0 Constant (const byte) print_person::i#0 = 0 Successful SSA optimization Pass2ConstantIdentification Converting *(pointer+n) to pointer[n] [25] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*) print_person::$0)) -- *((byte*)print_person::person#2 + OFFSET_STRUCT_PERSON_ID) Converting *(pointer+n) to pointer[n] [33] if((byte) 0!=*(*((byte[$10]*) print_person::$1) + (byte) print_person::i#2)) goto print_person::@2 -- *((byte[$10]*)print_person::person#2 + OFFSET_STRUCT_PERSON_NAME) Converting *(pointer+n) to pointer[n] [36] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*) print_person::$2) + (byte) print_person::i#2) -- *((byte[$10]*)print_person::person#2 + OFFSET_STRUCT_PERSON_NAME) Successful SSA optimization Pass2InlineDerefIdx Simplifying expression containing zero (byte*)print_person::person#2 in [24] (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID Simplifying expression containing zero (byte*)print_person::person#2 in [25] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID)) Successful SSA optimization PassNSimplifyExpressionWithZero Eliminating unused variable (struct Person) main::jesper#0 and assignment [2] (struct Person) main::jesper#0 ← struct-unwound {(byte) main::jesper_id#0, (byte[$10]) main::jesper_name#0} Eliminating unused variable (struct Person) main::henriette#0 and assignment [6] (struct Person) main::henriette#0 ← struct-unwound {(byte) main::henriette_id#0, (byte[$10]) main::henriette_name#0} Eliminating unused variable (byte*) print_person::$0 and assignment [10] (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 Eliminating unused variable (byte[$10]*) print_person::$1 and assignment [16] (byte[$10]*) print_person::$1 ← (byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME Eliminating unused variable (byte[$10]*) print_person::$2 and assignment [18] (byte[$10]*) print_person::$2 ← (byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME Eliminating unused constant (const byte) OFFSET_STRUCT_PERSON_ID Successful SSA optimization PassNEliminateUnusedVars Inlining constant with var siblings (const struct Person*) print_person::person#0 Inlining constant with var siblings (const struct Person*) print_person::person#1 Inlining constant with var siblings (const byte) print_person::i#0 Inlining constant with var siblings (const byte) idx#20 Constant inlined idx#20 = (byte) 0 Constant inlined $0 = (const byte[]) DIGIT#0 Constant inlined print_person::person#0 = (struct Person*)&(byte) main::jesper_id#0 Constant inlined print_person::i#0 = (byte) 0 Constant inlined print_person::person#1 = (struct Person*)&(byte) main::henriette_id#0 Successful SSA optimization Pass2ConstantInlining 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 @3 Adding NOP phi() at start of @end Adding NOP phi() at start of main::@2 CALL GRAPH Calls in [] to main:3 Calls in [main] to print_person:8 print_person:12 Created 4 initial phi equivalence classes Coalesced [11] idx#21 ← idx#16 Coalesced [20] idx#22 ← idx#5 Coalesced [29] print_person::i#4 ← print_person::i#1 Coalesced [30] idx#23 ← idx#6 Coalesced down to 4 phi equivalence classes Culled Empty Block (label) @1 Culled Empty Block (label) @3 Culled Empty Block (label) main::@2 Renumbering block @2 to @1 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) main::jesper_id#0 ← (byte) 4 [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 [6] call print_person to:main::@1 main::@1: scope:[main] from main [7] (byte) main::henriette_id#0 ← (byte) 7 [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 [9] call print_person to:main::@return main::@return: scope:[main] from main::@1 [10] return to:@return print_person: scope:[print_person] from main main::@1 [11] (byte) idx#13 ← phi( main/(byte) 0 main::@1/(byte) idx#16 ) [11] (struct Person*) print_person::person#2 ← phi( main/(struct Person*)&(byte) main::jesper_id#0 main::@1/(struct Person*)&(byte) main::henriette_id#0 ) [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) [13] (byte) idx#4 ← ++ (byte) idx#13 [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [15] (byte) idx#5 ← ++ (byte) idx#4 to:print_person::@1 print_person::@1: scope:[print_person] from print_person print_person::@2 [16] (byte) idx#14 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 ) [16] (byte) print_person::i#2 ← phi( print_person/(byte) 0 print_person::@2/(byte) print_person::i#1 ) [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 to:print_person::@3 print_person::@3: scope:[print_person] from print_person::@1 [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' [19] (byte) idx#16 ← ++ (byte) idx#14 to:print_person::@return print_person::@return: scope:[print_person] from print_person::@3 [20] return to:@return print_person::@2: scope:[print_person] from print_person::@1 [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) [22] (byte) idx#6 ← ++ (byte) idx#14 [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 to:print_person::@1 VARIABLE REGISTER WEIGHTS (byte[]) DIGIT (byte) Person::id (byte[$10]) Person::name (byte*) SCREEN (byte) idx (byte) idx#13 3.0 (byte) idx#14 9.75 (byte) idx#16 0.8 (byte) idx#4 3.0 (byte) idx#5 4.0 (byte) idx#6 11.0 (void()) main() (struct Person) main::henriette (byte) main::henriette_id (byte) main::henriette_id#0 20.0 (byte[$10]) main::henriette_name (byte[$10]) main::henriette_name#0 20.0 (struct Person) main::jesper (byte) main::jesper_id (byte) main::jesper_id#0 20.0 (byte[$10]) main::jesper_name (byte[$10]) main::jesper_name#0 20.0 (void()) print_person((struct Person*) print_person::person) (byte) print_person::i (byte) print_person::i#1 22.0 (byte) print_person::i#2 11.0 (struct Person*) print_person::person (struct Person*) print_person::person#2 Initial phi equivalence classes [ print_person::person#2 ] [ idx#13 idx#16 ] [ print_person::i#2 print_person::i#1 ] [ idx#14 idx#5 idx#6 ] Added variable idx#4 to zero page equivalence class [ idx#4 ] Complete equivalence classes [ print_person::person#2 ] [ idx#13 idx#16 ] [ print_person::i#2 print_person::i#1 ] [ idx#14 idx#5 idx#6 ] [ main::jesper_id#0 ] [ main::jesper_name#0 ] [ main::henriette_id#0 ] [ main::henriette_name#0 ] [ idx#4 ] Allocated zp ZP_WORD:2 [ print_person::person#2 ] Allocated zp ZP_BYTE:4 [ idx#13 idx#16 ] Allocated zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] Allocated zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] Allocated zp ZP_BYTE:7 [ main::jesper_id#0 ] Allocated zp ZP_WORD:8 [ main::jesper_name#0 ] Allocated zp ZP_BYTE:10 [ main::henriette_id#0 ] Allocated zp ZP_WORD:11 [ main::henriette_name#0 ] Allocated zp ZP_BYTE:13 [ idx#4 ] INITIAL ASM Target platform is c64basic / MOS6502X // File Comments // Example of a struct containing an array // It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers. // https://gitlab.com/camelot/kickc/issues/312 // Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) .pc = $80d "Program" // Global Constants & labels .const OFFSET_STRUCT_PERSON_NAME = 1 .label SCREEN = $400 .label idx = $d .label idx_5 = 6 .label idx_6 = 6 .label idx_13 = 4 .label idx_14 = 6 .label idx_16 = 4 // @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 jesper_id = 7 .label jesper_name = 8 .label henriette_id = $a .label henriette_name = $b // [4] (byte) main::jesper_id#0 ← (byte) 4 -- vbuz1=vbuc1 lda #4 sta.z jesper_id // [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 -- pbuz1=pbuc1 lda #<_4 sta.z jesper_name lda #>_4 sta.z jesper_name+1 // [6] call print_person // [11] phi from main to print_person [phi:main->print_person] print_person_from_main: // [11] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuz1=vbuc1 lda #0 sta.z idx_13 // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::jesper_id#0 [phi:main->print_person#1] -- pssz1=pssc1 lda #jesper_id sta.z print_person.person+1 jsr print_person jmp b1 // main::@1 b1: // [7] (byte) main::henriette_id#0 ← (byte) 7 -- vbuz1=vbuc1 lda #7 sta.z henriette_id // [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 -- pbuz1=pbuc1 lda #<_5 sta.z henriette_name lda #>_5 sta.z henriette_name+1 // [9] call print_person // [11] phi from main::@1 to print_person [phi:main::@1->print_person] print_person_from_b1: // [11] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::henriette_id#0 [phi:main::@1->print_person#1] -- pssz1=pssc1 lda #henriette_id sta.z print_person.person+1 jsr print_person jmp breturn // main::@return breturn: // [10] return rts _4: .text "jesper" .byte 0 _5: .text "henriette" .byte 0 } // print_person // print_person(struct Person* zeropage(2) person) print_person: { .label i = 5 .label person = 2 // [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_(_deref_pbuz2) ldx.z idx_13 ldy #0 lda (person),y tay lda DIGIT,y sta SCREEN,x // [13] (byte) idx#4 ← ++ (byte) idx#13 -- vbuz1=_inc_vbuz2 ldy.z idx_13 iny sty.z idx // [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2 lda #' ' ldy.z idx sta SCREEN,y // [15] (byte) idx#5 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz2 ldy.z idx iny sty.z idx_5 // [16] phi from print_person to print_person::@1 [phi:print_person->print_person::@1] b1_from_print_person: // [16] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy // [16] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuz1=vbuc1 lda #0 sta.z i jmp b1 // print_person::@1 b1: // [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_(pptz1_derefidx_vbuc2)_derefidx_vbuz2_then_la1 ldy #OFFSET_STRUCT_PERSON_NAME lda (person),y sta.z $fe iny lda (person),y sta.z $ff ldy.z i lda ($fe),y cmp #0 bne b2 jmp b3 // print_person::@3 b3: // [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2 lda #' ' ldy.z idx_14 sta SCREEN,y // [19] (byte) idx#16 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz2 ldy.z idx_14 iny sty.z idx_16 jmp breturn // print_person::@return breturn: // [20] return rts // print_person::@2 b2: // [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) -- pbuc1_derefidx_vbuz1=(pptz2_derefidx_vbuc2)_derefidx_vbuz3 ldx.z idx_14 ldy #OFFSET_STRUCT_PERSON_NAME lda (person),y sta.z $fe iny lda (person),y sta.z $ff ldy.z i lda ($fe),y sta SCREEN,x // [22] (byte) idx#6 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz1 inc.z idx_6 // [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuz1=_inc_vbuz1 inc.z i // [16] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1] b1_from_b2: // [16] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy // [16] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy jmp b1 } // File Data DIGIT: .text "0123456789" .byte 0 REGISTER UPLIFT POTENTIAL REGISTERS Statement [4] (byte) main::jesper_id#0 ← (byte) 4 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [7] (byte) main::henriette_id#0 ← (byte) 7 [ idx#16 ] ( main:2 [ idx#16 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ idx#13 idx#16 ] Statement [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 [ idx#16 ] ( main:2 [ idx#16 ] ) always clobbers reg byte a Statement [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) [ print_person::person#2 idx#13 ] ( main:2::print_person:6 [ print_person::person#2 idx#13 ] main:2::print_person:9 [ print_person::person#2 idx#13 ] ) always clobbers reg byte a reg byte y Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ idx#13 idx#16 ] Statement [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person#2 idx#4 ] ( main:2::print_person:6 [ print_person::person#2 idx#4 ] main:2::print_person:9 [ print_person::person#2 idx#4 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:13 [ idx#4 ] Statement [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:6 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:9 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y Removing always clobbered register reg byte a as potential for zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] Removing always clobbered register reg byte y as potential for zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] Removing always clobbered register reg byte y as potential for zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] Statement [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' [ idx#14 ] ( main:2::print_person:6 [ idx#14 ] main:2::print_person:9 [ idx#14 ] ) always clobbers reg byte a Statement [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:6 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:9 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y Statement [4] (byte) main::jesper_id#0 ← (byte) 4 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [7] (byte) main::henriette_id#0 ← (byte) 7 [ idx#16 ] ( main:2 [ idx#16 ] ) always clobbers reg byte a Statement [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 [ idx#16 ] ( main:2 [ idx#16 ] ) always clobbers reg byte a Statement [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) [ print_person::person#2 idx#13 ] ( main:2::print_person:6 [ print_person::person#2 idx#13 ] main:2::print_person:9 [ print_person::person#2 idx#13 ] ) always clobbers reg byte a reg byte y Statement [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person#2 idx#4 ] ( main:2::print_person:6 [ print_person::person#2 idx#4 ] main:2::print_person:9 [ print_person::person#2 idx#4 ] ) always clobbers reg byte a Statement [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:6 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:9 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y Statement [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' [ idx#14 ] ( main:2::print_person:6 [ idx#14 ] main:2::print_person:9 [ idx#14 ] ) always clobbers reg byte a Statement [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:6 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:9 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y Potential registers zp ZP_WORD:2 [ print_person::person#2 ] : zp ZP_WORD:2 , Potential registers zp ZP_BYTE:4 [ idx#13 idx#16 ] : zp ZP_BYTE:4 , reg byte x , Potential registers zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] : zp ZP_BYTE:5 , reg byte x , Potential registers zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] : zp ZP_BYTE:6 , reg byte x , Potential registers zp ZP_BYTE:7 [ main::jesper_id#0 ] : zp ZP_BYTE:7 , Potential registers zp ZP_WORD:8 [ main::jesper_name#0 ] : zp ZP_WORD:8 , Potential registers zp ZP_BYTE:10 [ main::henriette_id#0 ] : zp ZP_BYTE:10 , Potential registers zp ZP_WORD:11 [ main::henriette_name#0 ] : zp ZP_WORD:11 , Potential registers zp ZP_BYTE:13 [ idx#4 ] : zp ZP_BYTE:13 , reg byte x , reg byte y , REGISTER UPLIFT SCOPES Uplift Scope [main] 20: zp ZP_BYTE:7 [ main::jesper_id#0 ] 20: zp ZP_WORD:8 [ main::jesper_name#0 ] 20: zp ZP_BYTE:10 [ main::henriette_id#0 ] 20: zp ZP_WORD:11 [ main::henriette_name#0 ] Uplift Scope [print_person] 33: zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] 0: zp ZP_WORD:2 [ print_person::person#2 ] Uplift Scope [] 24.75: zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] 3.8: zp ZP_BYTE:4 [ idx#13 idx#16 ] 3: zp ZP_BYTE:13 [ idx#4 ] Uplift Scope [Person] Uplifting [main] best 1121 combination zp ZP_BYTE:7 [ main::jesper_id#0 ] zp ZP_WORD:8 [ main::jesper_name#0 ] zp ZP_BYTE:10 [ main::henriette_id#0 ] zp ZP_WORD:11 [ main::henriette_name#0 ] Uplifting [print_person] best 1121 combination zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] zp ZP_WORD:2 [ print_person::person#2 ] Uplifting [] best 1031 combination reg byte x [ idx#14 idx#5 idx#6 ] reg byte x [ idx#13 idx#16 ] reg byte x [ idx#4 ] Uplifting [Person] best 1031 combination Attempting to uplift remaining variables inzp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] Uplifting [print_person] best 1031 combination zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] Attempting to uplift remaining variables inzp ZP_BYTE:7 [ main::jesper_id#0 ] Uplifting [main] best 1031 combination zp ZP_BYTE:7 [ main::jesper_id#0 ] Attempting to uplift remaining variables inzp ZP_BYTE:10 [ main::henriette_id#0 ] Uplifting [main] best 1031 combination zp ZP_BYTE:10 [ main::henriette_id#0 ] Allocated (was zp ZP_BYTE:5) zp ZP_BYTE:4 [ print_person::i#2 print_person::i#1 ] Allocated (was zp ZP_BYTE:7) zp ZP_BYTE:5 [ main::jesper_id#0 ] Allocated (was zp ZP_WORD:8) zp ZP_WORD:6 [ main::jesper_name#0 ] Allocated (was zp ZP_BYTE:10) zp ZP_BYTE:8 [ main::henriette_id#0 ] Allocated (was zp ZP_WORD:11) zp ZP_WORD:9 [ main::henriette_name#0 ] ASSEMBLER BEFORE OPTIMIZATION // File Comments // Example of a struct containing an array // It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers. // https://gitlab.com/camelot/kickc/issues/312 // Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) .pc = $80d "Program" // Global Constants & labels .const OFFSET_STRUCT_PERSON_NAME = 1 .label SCREEN = $400 // @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 jesper_id = 5 .label jesper_name = 6 .label henriette_id = 8 .label henriette_name = 9 // [4] (byte) main::jesper_id#0 ← (byte) 4 -- vbuz1=vbuc1 lda #4 sta.z jesper_id // [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 -- pbuz1=pbuc1 lda #<_4 sta.z jesper_name lda #>_4 sta.z jesper_name+1 // [6] call print_person // [11] phi from main to print_person [phi:main->print_person] print_person_from_main: // [11] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1 ldx #0 // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::jesper_id#0 [phi:main->print_person#1] -- pssz1=pssc1 lda #jesper_id sta.z print_person.person+1 jsr print_person jmp b1 // main::@1 b1: // [7] (byte) main::henriette_id#0 ← (byte) 7 -- vbuz1=vbuc1 lda #7 sta.z henriette_id // [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 -- pbuz1=pbuc1 lda #<_5 sta.z henriette_name lda #>_5 sta.z henriette_name+1 // [9] call print_person // [11] phi from main::@1 to print_person [phi:main::@1->print_person] print_person_from_b1: // [11] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::henriette_id#0 [phi:main::@1->print_person#1] -- pssz1=pssc1 lda #henriette_id sta.z print_person.person+1 jsr print_person jmp breturn // main::@return breturn: // [10] return rts _4: .text "jesper" .byte 0 _5: .text "henriette" .byte 0 } // print_person // print_person(struct Person* zeropage(2) person) print_person: { .label i = 4 .label person = 2 // [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1) ldy #0 lda (person),y tay lda DIGIT,y sta SCREEN,x // [13] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuxx inx // [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 lda #' ' sta SCREEN,x // [15] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx inx // [16] phi from print_person to print_person::@1 [phi:print_person->print_person::@1] b1_from_print_person: // [16] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy // [16] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuz1=vbuc1 lda #0 sta.z i jmp b1 // print_person::@1 b1: // [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_(pptz1_derefidx_vbuc2)_derefidx_vbuz2_then_la1 ldy #OFFSET_STRUCT_PERSON_NAME lda (person),y sta.z $fe iny lda (person),y sta.z $ff ldy.z i lda ($fe),y cmp #0 bne b2 jmp b3 // print_person::@3 b3: // [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 lda #' ' sta SCREEN,x // [19] (byte) idx#16 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx inx jmp breturn // print_person::@return breturn: // [20] return rts // print_person::@2 b2: // [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=(pptz1_derefidx_vbuc2)_derefidx_vbuz2 ldy #OFFSET_STRUCT_PERSON_NAME lda (person),y sta.z $fe iny lda (person),y sta.z $ff ldy.z i lda ($fe),y sta SCREEN,x // [22] (byte) idx#6 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx inx // [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuz1=_inc_vbuz1 inc.z i // [16] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1] b1_from_b2: // [16] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy // [16] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy jmp b1 } // File Data DIGIT: .text "0123456789" .byte 0 ASSEMBLER OPTIMIZATIONS Removing instruction jmp b1 Removing instruction jmp bend Removing instruction jmp b1 Removing instruction jmp breturn Removing instruction jmp b1 Removing instruction jmp b3 Removing instruction jmp breturn Succesful ASM optimization Pass5NextJumpElimination Removing instruction b1_from_bbegin: Removing instruction b1: Removing instruction bend_from_b1: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction bend: Removing instruction print_person_from_main: Removing instruction b1: Removing instruction print_person_from_b1: Removing instruction breturn: Removing instruction b1_from_print_person: Removing instruction b3: Removing instruction breturn: Removing instruction b1_from_b2: Succesful ASM optimization Pass5UnusedLabelElimination Updating BasicUpstart to call main directly Removing instruction jsr main Succesful ASM optimization Pass5SkipBegin Removing instruction bbegin: Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE (label) @1 (label) @begin (label) @end (byte[]) DIGIT (const byte[]) DIGIT#0 DIGIT = (string) "0123456789" (const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1 (byte) Person::id (byte[$10]) Person::name (byte*) SCREEN (const byte*) SCREEN#0 SCREEN = (byte*) 1024 (byte) idx (byte) idx#13 reg byte x 3.0 (byte) idx#14 reg byte x 9.75 (byte) idx#16 reg byte x 0.8 (byte) idx#4 reg byte x 3.0 (byte) idx#5 reg byte x 4.0 (byte) idx#6 reg byte x 11.0 (void()) main() (const string) main::$4 $4 = (string) "jesper" (const string) main::$5 $5 = (string) "henriette" (label) main::@1 (label) main::@return (struct Person) main::henriette (byte) main::henriette_id (byte) main::henriette_id#0 henriette_id zp ZP_BYTE:8 20.0 (byte[$10]) main::henriette_name (byte[$10]) main::henriette_name#0 henriette_name zp ZP_WORD:9 20.0 (struct Person) main::jesper (byte) main::jesper_id (byte) main::jesper_id#0 jesper_id zp ZP_BYTE:5 20.0 (byte[$10]) main::jesper_name (byte[$10]) main::jesper_name#0 jesper_name zp ZP_WORD:6 20.0 (void()) print_person((struct Person*) print_person::person) (label) print_person::@1 (label) print_person::@2 (label) print_person::@3 (label) print_person::@return (byte) print_person::i (byte) print_person::i#1 i zp ZP_BYTE:4 22.0 (byte) print_person::i#2 i zp ZP_BYTE:4 11.0 (struct Person*) print_person::person (struct Person*) print_person::person#2 person zp ZP_WORD:2 zp ZP_WORD:2 [ print_person::person#2 ] reg byte x [ idx#13 idx#16 ] zp ZP_BYTE:4 [ print_person::i#2 print_person::i#1 ] reg byte x [ idx#14 idx#5 idx#6 ] zp ZP_BYTE:5 [ main::jesper_id#0 ] zp ZP_WORD:6 [ main::jesper_name#0 ] zp ZP_BYTE:8 [ main::henriette_id#0 ] zp ZP_WORD:9 [ main::henriette_name#0 ] reg byte x [ idx#4 ] FINAL ASSEMBLER Score: 950 // File Comments // Example of a struct containing an array // It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers. // https://gitlab.com/camelot/kickc/issues/312 // Upstart .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" // Global Constants & labels .const OFFSET_STRUCT_PERSON_NAME = 1 .label SCREEN = $400 // @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 jesper_id = 5 .label jesper_name = 6 .label henriette_id = 8 .label henriette_name = 9 // jesper = { 4, "jesper" } // [4] (byte) main::jesper_id#0 ← (byte) 4 -- vbuz1=vbuc1 lda #4 sta.z jesper_id // [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 -- pbuz1=pbuc1 lda #<_4 sta.z jesper_name lda #>_4 sta.z jesper_name+1 // print_person(&jesper) // [6] call print_person // [11] phi from main to print_person [phi:main->print_person] // [11] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1 ldx #0 // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::jesper_id#0 [phi:main->print_person#1] -- pssz1=pssc1 lda #jesper_id sta.z print_person.person+1 jsr print_person // main::@1 // henriette = { 7, "henriette" } // [7] (byte) main::henriette_id#0 ← (byte) 7 -- vbuz1=vbuc1 lda #7 sta.z henriette_id // [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 -- pbuz1=pbuc1 lda #<_5 sta.z henriette_name lda #>_5 sta.z henriette_name+1 // print_person(&henriette) // [9] call print_person // [11] phi from main::@1 to print_person [phi:main::@1->print_person] // [11] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::henriette_id#0 [phi:main::@1->print_person#1] -- pssz1=pssc1 lda #henriette_id sta.z print_person.person+1 jsr print_person // main::@return // } // [10] return rts _4: .text "jesper" .byte 0 _5: .text "henriette" .byte 0 } // print_person // print_person(struct Person* zeropage(2) person) print_person: { .label i = 4 .label person = 2 // SCREEN[idx++] = DIGIT[person->id] // [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1) ldy #0 lda (person),y tay lda DIGIT,y sta SCREEN,x // SCREEN[idx++] = DIGIT[person->id]; // [13] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuxx inx // SCREEN[idx++] = ' ' // [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 lda #' ' sta SCREEN,x // SCREEN[idx++] = ' '; // [15] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx inx // [16] phi from print_person to print_person::@1 [phi:print_person->print_person::@1] // [16] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy // [16] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuz1=vbuc1 lda #0 sta.z i // print_person::@1 b1: // for(byte i=0; person->name[i]; i++) // [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_(pptz1_derefidx_vbuc2)_derefidx_vbuz2_then_la1 ldy #OFFSET_STRUCT_PERSON_NAME lda (person),y sta.z $fe iny lda (person),y sta.z $ff ldy.z i lda ($fe),y cmp #0 bne b2 // print_person::@3 // SCREEN[idx++] = ' ' // [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 lda #' ' sta SCREEN,x // SCREEN[idx++] = ' '; // [19] (byte) idx#16 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx inx // print_person::@return // } // [20] return rts // print_person::@2 b2: // SCREEN[idx++] = person->name[i] // [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=(pptz1_derefidx_vbuc2)_derefidx_vbuz2 ldy #OFFSET_STRUCT_PERSON_NAME lda (person),y sta.z $fe iny lda (person),y sta.z $ff ldy.z i lda ($fe),y sta SCREEN,x // SCREEN[idx++] = person->name[i]; // [22] (byte) idx#6 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx inx // for(byte i=0; person->name[i]; i++) // [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuz1=_inc_vbuz1 inc.z i // [16] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1] // [16] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy // [16] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy jmp b1 } // File Data DIGIT: .text "0123456789" .byte 0