diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorSizeOf.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorSizeOf.java index 7e651c5eb..3a4a58e29 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorSizeOf.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorSizeOf.java @@ -48,6 +48,22 @@ public class OperatorSizeOf extends OperatorUnary { return typeSizeConstant.getConstantRef(); } + /** + * Fix the size value of the constant variable if needed. + * Sizes for structs and other complex types is not known until late in Pass1, so they may need fixing. + * @param programScope The program scope (used for finding/adding the constant). + * @param type The type to get the variable for + */ + public static void fixSizeOfConstantVar(ProgramScope programScope, SymbolType type) { + String typeConstName = getSizeofConstantName(type); + Variable typeSizeConstant = programScope.getConstant(typeConstName); + if(typeSizeConstant != null) { + // Constant found - update it + long typeSize = type.getSizeBytes(); + typeSizeConstant.setInitValue(new ConstantInteger(typeSize&0xff, SymbolType.BYTE)); + } + } + /** * Get the name of the constant variable containing the size of a specific type * diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java index 7b7b1559b..afc04af4a 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java @@ -612,7 +612,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor@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 point1 = 2 + // [4] *((byte*)&(struct Point) main::point1) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta.z point1 + // [5] *((byte*)&(struct Point) main::point1) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta.z point1 + // [6] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← (byte) 'j' -- _deref_pbuc1=vbuc2 + lda #'j' + sta point1+OFFSET_STRUCT_POINT_INITIALS + // [7] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) ← (byte) 'g' -- _deref_pbuc1=vbuc2 + lda #'g' + sta point1+OFFSET_STRUCT_POINT_INITIALS+1 + // [8] *((const byte*) SCREEN) ← *((byte*)&(struct Point) main::point1) -- _deref_pbuc1=_deref_pbuc2 + lda.z point1 + sta SCREEN + // [9] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2 + lda point1+OFFSET_STRUCT_POINT_INITIALS + sta SCREEN+1 + // [10] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) -- _deref_pbuc1=_deref_pbuc2 + lda point1+OFFSET_STRUCT_POINT_INITIALS+1 + sta SCREEN+2 + jmp __breturn + // main::@return + __breturn: + // [11] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((byte*)&(struct Point) main::point1) ← (byte) 0 [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a +Statement [5] *((byte*)&(struct Point) main::point1) ← (byte) 2 [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a +Statement [6] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← (byte) 'j' [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a +Statement [7] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) ← (byte) 'g' [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a +Statement [8] *((const byte*) SCREEN) ← *((byte*)&(struct Point) main::point1) [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a +Statement [9] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a +Statement [10] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) [ ] ( main:2 [ ] ) always clobbers reg byte a +Potential registers zp[3]:2 [ main::point1 ] : zp[3]:2 , + +REGISTER UPLIFT SCOPES +Uplift Scope [Point] +Uplift Scope [main] 0: zp[3]:2 [ main::point1 ] +Uplift Scope [] + +Uplifting [Point] best 66 combination +Uplifting [main] best 66 combination zp[3]:2 [ main::point1 ] +Uplifting [] best 66 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Minimal struct with C-Standard behavior - member array + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label SCREEN = $400 + .const OFFSET_STRUCT_POINT_INITIALS = 1 + // @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 point1 = 2 + // [4] *((byte*)&(struct Point) main::point1) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta.z point1 + // [5] *((byte*)&(struct Point) main::point1) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta.z point1 + // [6] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← (byte) 'j' -- _deref_pbuc1=vbuc2 + lda #'j' + sta point1+OFFSET_STRUCT_POINT_INITIALS + // [7] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) ← (byte) 'g' -- _deref_pbuc1=vbuc2 + lda #'g' + sta point1+OFFSET_STRUCT_POINT_INITIALS+1 + // [8] *((const byte*) SCREEN) ← *((byte*)&(struct Point) main::point1) -- _deref_pbuc1=_deref_pbuc2 + lda.z point1 + sta SCREEN + // [9] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2 + lda point1+OFFSET_STRUCT_POINT_INITIALS + sta SCREEN+1 + // [10] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) -- _deref_pbuc1=_deref_pbuc2 + lda point1+OFFSET_STRUCT_POINT_INITIALS+1 + sta SCREEN+2 + jmp __breturn + // main::@return + __breturn: + // [11] return + rts +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __bend +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing label __bbegin with __b1 +Removing instruction __bbegin: +Removing instruction __b1_from___bbegin: +Removing instruction __bend_from___b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction __bend: +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction __b1: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(const byte) OFFSET_STRUCT_POINT_INITIALS = (byte) 1 +(const byte*) Point::initials[(number) 2] = { fill( 2, 0) } +(byte) Point::x +(const byte*) SCREEN = (byte*) 1024 +(void()) main() +(label) main::@return +(struct Point) main::point1 loadstore zp[3]:2 + +zp[3]:2 [ main::point1 ] + + +FINAL ASSEMBLER +Score: 51 + + // File Comments +// Minimal struct with C-Standard behavior - member array + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .label SCREEN = $400 + .const OFFSET_STRUCT_POINT_INITIALS = 1 + // @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 point1 = 2 + // point1 + // [4] *((byte*)&(struct Point) main::point1) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta.z point1 + // point1.x = 2 + // [5] *((byte*)&(struct Point) main::point1) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta.z point1 + // point1.initials[0] = 'j' + // [6] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← (byte) 'j' -- _deref_pbuc1=vbuc2 + lda #'j' + sta point1+OFFSET_STRUCT_POINT_INITIALS + // point1.initials[1] = 'g' + // [7] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) ← (byte) 'g' -- _deref_pbuc1=vbuc2 + lda #'g' + sta point1+OFFSET_STRUCT_POINT_INITIALS+1 + // SCREEN[0] = point1.x + // [8] *((const byte*) SCREEN) ← *((byte*)&(struct Point) main::point1) -- _deref_pbuc1=_deref_pbuc2 + lda.z point1 + sta SCREEN + // SCREEN[1] = point1.initials[0] + // [9] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2 + lda point1+OFFSET_STRUCT_POINT_INITIALS + sta SCREEN+1 + // SCREEN[2] = point1.initials[1] + // [10] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) -- _deref_pbuc1=_deref_pbuc2 + lda point1+OFFSET_STRUCT_POINT_INITIALS+1 + sta SCREEN+2 + // main::@return + // } + // [11] return + rts +} + // File Data + diff --git a/src/test/ref/struct-24.sym b/src/test/ref/struct-24.sym new file mode 100644 index 000000000..4de77febc --- /dev/null +++ b/src/test/ref/struct-24.sym @@ -0,0 +1,12 @@ +(label) @1 +(label) @begin +(label) @end +(const byte) OFFSET_STRUCT_POINT_INITIALS = (byte) 1 +(const byte*) Point::initials[(number) 2] = { fill( 2, 0) } +(byte) Point::x +(const byte*) SCREEN = (byte*) 1024 +(void()) main() +(label) main::@return +(struct Point) main::point1 loadstore zp[3]:2 + +zp[3]:2 [ main::point1 ] diff --git a/src/test/ref/struct-25.asm b/src/test/ref/struct-25.asm new file mode 100644 index 000000000..2ff179a69 --- /dev/null +++ b/src/test/ref/struct-25.asm @@ -0,0 +1,11 @@ +// Minimal struct with C-Standard behavior - member array sizeof +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label SCREEN = $400 + .const SIZEOF_STRUCT_POINT = 4 +main: { + lda #SIZEOF_STRUCT_POINT + sta SCREEN + rts +} diff --git a/src/test/ref/struct-25.cfg b/src/test/ref/struct-25.cfg new file mode 100644 index 000000000..e34e0f15e --- /dev/null +++ b/src/test/ref/struct-25.cfg @@ -0,0 +1,17 @@ +@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] *((const byte*) SCREEN) ← (const byte) SIZEOF_STRUCT_POINT + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return diff --git a/src/test/ref/struct-25.log b/src/test/ref/struct-25.log new file mode 100644 index 000000000..67384a572 --- /dev/null +++ b/src/test/ref/struct-25.log @@ -0,0 +1,232 @@ +Fixing struct type SIZE_OF struct Point to 4 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 + +(void()) main() +main: scope:[main] from @1 + *((const byte*) SCREEN + (number) 0) ← (const byte) SIZEOF_STRUCT_POINT + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(const byte*) Point::initials[(number) 2] = { fill( 2, 0) } +(signed word) Point::x +(const byte*) SCREEN = (byte*)(number) $400 +(const byte) SIZEOF_STRUCT_POINT = (byte) 4 +(void()) main() +(label) main::@return + +Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 0) ← (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 0 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Simplifying expression containing zero SCREEN in [0] *((const byte*) SCREEN + (byte) 0) ← (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization PassNSimplifyExpressionWithZero +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Culled Empty Block (label) @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] *((const byte*) SCREEN) ← (const byte) SIZEOF_STRUCT_POINT + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(signed word) Point::x +(void()) main() + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// Minimal struct with C-Standard behavior - member array sizeof + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label SCREEN = $400 + .const SIZEOF_STRUCT_POINT = 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: { + // [4] *((const byte*) SCREEN) ← (const byte) SIZEOF_STRUCT_POINT -- _deref_pbuc1=vbuc2 + lda #SIZEOF_STRUCT_POINT + sta SCREEN + jmp __breturn + // main::@return + __breturn: + // [5] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((const byte*) SCREEN) ← (const byte) SIZEOF_STRUCT_POINT [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [Point] +Uplift Scope [main] +Uplift Scope [] + +Uplifting [Point] best 27 combination +Uplifting [main] best 27 combination +Uplifting [] best 27 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Minimal struct with C-Standard behavior - member array sizeof + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label SCREEN = $400 + .const SIZEOF_STRUCT_POINT = 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: { + // [4] *((const byte*) SCREEN) ← (const byte) SIZEOF_STRUCT_POINT -- _deref_pbuc1=vbuc2 + lda #SIZEOF_STRUCT_POINT + sta SCREEN + jmp __breturn + // main::@return + __breturn: + // [5] return + rts +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __bend +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing label __bbegin with __b1 +Removing instruction __bbegin: +Removing instruction __b1_from___bbegin: +Removing instruction __bend_from___b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction __bend: +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction __b1: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(const byte*) Point::initials[(number) 2] = { fill( 2, 0) } +(signed word) Point::x +(const byte*) SCREEN = (byte*) 1024 +(const byte) SIZEOF_STRUCT_POINT = (byte) 4 +(void()) main() +(label) main::@return + + + +FINAL ASSEMBLER +Score: 12 + + // File Comments +// Minimal struct with C-Standard behavior - member array sizeof + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .label SCREEN = $400 + .const SIZEOF_STRUCT_POINT = 4 + // @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: { + // SCREEN[0] = sizeof(struct Point) + // [4] *((const byte*) SCREEN) ← (const byte) SIZEOF_STRUCT_POINT -- _deref_pbuc1=vbuc2 + lda #SIZEOF_STRUCT_POINT + sta SCREEN + // main::@return + // } + // [5] return + rts +} + // File Data + diff --git a/src/test/ref/struct-25.sym b/src/test/ref/struct-25.sym new file mode 100644 index 000000000..3fa6c8161 --- /dev/null +++ b/src/test/ref/struct-25.sym @@ -0,0 +1,10 @@ +(label) @1 +(label) @begin +(label) @end +(const byte*) Point::initials[(number) 2] = { fill( 2, 0) } +(signed word) Point::x +(const byte*) SCREEN = (byte*) 1024 +(const byte) SIZEOF_STRUCT_POINT = (byte) 4 +(void()) main() +(label) main::@return + diff --git a/src/test/ref/struct-ptr-23.log b/src/test/ref/struct-ptr-23.log index 394ed2d10..858120c71 100644 --- a/src/test/ref/struct-ptr-23.log +++ b/src/test/ref/struct-ptr-23.log @@ -1,6 +1,8 @@ Fixing struct type size struct Person to 5 Fixing struct type size struct Person to 5 Fixing struct type size struct Person to 5 +Fixing struct type SIZE_OF struct Person to 5 +Fixing struct type SIZE_OF struct Person to 5 Fixing pointer increment (struct Person*) main::person ← ++ (struct Person*) main::person Rewriting struct pointer member access *((struct Person*) print_person::person).id Rewriting struct pointer member access *((struct Person*) print_person::person).initials diff --git a/src/test/ref/struct-ptr-31.log b/src/test/ref/struct-ptr-31.log index 7113a3b12..8c3e500e8 100644 --- a/src/test/ref/struct-ptr-31.log +++ b/src/test/ref/struct-ptr-31.log @@ -1,5 +1,7 @@ Fixing struct type size struct Person to 17 Fixing struct type size struct Person to 17 +Fixing struct type SIZE_OF struct Person to 17 +Fixing struct type SIZE_OF struct Person to 17 Fixing constant pointer addition (const struct Person*) persons+(number) 1 Rewriting struct pointer member access *((struct Person*) print_person::person).id Rewriting struct pointer member access *((struct Person*) print_person::person).name diff --git a/src/test/ref/struct-ptr-32.log b/src/test/ref/struct-ptr-32.log index 1c7d215e4..aa2d43489 100644 --- a/src/test/ref/struct-ptr-32.log +++ b/src/test/ref/struct-ptr-32.log @@ -1,5 +1,7 @@ Fixing struct type size struct Person to 16 Fixing struct type size struct Person to 16 +Fixing struct type SIZE_OF struct Person to 16 +Fixing struct type SIZE_OF struct Person to 16 Fixing pointer increment (struct Person*) main::person ← ++ (struct Person*) main::person Fixing pointer array-indexing *((const struct Person*) persons + (number) 0) Fixing pointer array-indexing *((const struct Person*) persons + (number) 1) diff --git a/src/test/ref/struct-ptr-33.log b/src/test/ref/struct-ptr-33.log index b69b442d5..ca6d45b3a 100644 --- a/src/test/ref/struct-ptr-33.log +++ b/src/test/ref/struct-ptr-33.log @@ -1,5 +1,7 @@ Fixing struct type size struct Person to 16 Fixing struct type size struct Person to 16 +Fixing struct type SIZE_OF struct Person to 16 +Fixing struct type SIZE_OF struct Person to 16 Fixing pointer increment (struct Person*) main::person ← ++ (struct Person*) main::person Rewriting struct pointer member access *((struct Person*) main::person).name Rewriting struct pointer member access *((struct Person*) main::person).name