diff --git a/src/main/java/dk/camelot64/kickc/model/VariableBuilder.java b/src/main/java/dk/camelot64/kickc/model/VariableBuilder.java index a2fae80a3..5ae238e9b 100644 --- a/src/main/java/dk/camelot64/kickc/model/VariableBuilder.java +++ b/src/main/java/dk/camelot64/kickc/model/VariableBuilder.java @@ -48,6 +48,7 @@ public class VariableBuilder { /** * Build the variable with the properties derived from type, scope, directives and configuration. + * * @return The variable */ public Variable build() { @@ -222,11 +223,15 @@ public class VariableBuilder { */ public boolean isSingleStaticAssignment() { if(hasDirective(Directive.FormMa.class)) + // the __ma directive forces multiple-assignment + return false; + else if(isNoModify()) + // (volatile) no-modify variables must be load/store + // TODO: Change to isVolatile()! return false; - else if(!isConstant()) - return true; else - return false; + // All others are single-static-assignment (by default) + return true; } /** diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java index f9f5d15f8..55b09bab8 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java @@ -266,8 +266,8 @@ 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: { + // [4] *((const byte*) SCREEN) ← (byte) i -- _deref_pbuc1=vbuz1 + lda.z i + sta SCREEN + jmp __breturn + // main::@return + __breturn: + // [5] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [0] (byte) i ← (byte) 7 [ i ] ( [ i ] ) always clobbers reg byte a +Statement [4] *((const byte*) SCREEN) ← (byte) i [ ] ( main:2 [ ] ) always clobbers reg byte a +Potential registers zp[1]:2 [ i ] : zp[1]:2 , + +REGISTER UPLIFT SCOPES +Uplift Scope [] 2: zp[1]:2 [ i ] +Uplift Scope [main] + +Uplifting [] best 33 combination zp[1]:2 [ i ] +Uplifting [main] best 33 combination +Attempting to uplift remaining variables inzp[1]:2 [ i ] +Uplifting [] best 33 combination zp[1]:2 [ i ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test that a volatile nomodify-variable works as expected + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label SCREEN = $400 + .label i = 2 + // @begin +__bbegin: + // [0] (byte) i ← (byte) 7 -- vbuz1=vbuc1 + lda #7 + sta.z i + // [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) ← (byte) i -- _deref_pbuc1=vbuz1 + lda.z i + 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 +Removing instruction __b1_from___bbegin: +Removing instruction __bend_from___b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction __b1: +Removing instruction __bend: +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Adding RTS to root block +Succesful ASM optimization Pass5AddMainRts + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(const byte*) SCREEN = (byte*) 1024 +(byte) i loadstore zp[1]:2 2.0 +(void()) main() +(label) main::@return + +zp[1]:2 [ i ] + + +FINAL ASSEMBLER +Score: 30 + + // File Comments +// Test that a volatile nomodify-variable works as expected + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label SCREEN = $400 + .label i = 2 + // @begin +__bbegin: + // i = 7 + // [0] (byte) i ← (byte) 7 -- vbuz1=vbuc1 + lda #7 + sta.z i + // [1] phi from @begin to @1 [phi:@begin->@1] + // @1 + // [2] call main + jsr main + rts + // [3] phi from @1 to @end [phi:@1->@end] + // @end + // main +main: { + // SCREEN[0] = i + // [4] *((const byte*) SCREEN) ← (byte) i -- _deref_pbuc1=vbuz1 + lda.z i + sta SCREEN + // main::@return + // } + // [5] return + rts +} + // File Data + diff --git a/src/test/ref/nomodify-3.sym b/src/test/ref/nomodify-3.sym new file mode 100644 index 000000000..5cd20bd4e --- /dev/null +++ b/src/test/ref/nomodify-3.sym @@ -0,0 +1,9 @@ +(label) @1 +(label) @begin +(label) @end +(const byte*) SCREEN = (byte*) 1024 +(byte) i loadstore zp[1]:2 2.0 +(void()) main() +(label) main::@return + +zp[1]:2 [ i ] diff --git a/src/test/ref/nomodify-4.asm b/src/test/ref/nomodify-4.asm new file mode 100644 index 000000000..d1108d52e --- /dev/null +++ b/src/test/ref/nomodify-4.asm @@ -0,0 +1,20 @@ +// Test that a nomodify parameter works +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label SCREEN = $400 +main: { + lda #'a' + sta.z print.c + jsr print + lda #'b' + sta.z print.c + jsr print + rts +} +print: { + .label c = 2 + lda.z c + sta SCREEN + rts +} diff --git a/src/test/ref/nomodify-4.cfg b/src/test/ref/nomodify-4.cfg new file mode 100644 index 000000000..b30edf60c --- /dev/null +++ b/src/test/ref/nomodify-4.cfg @@ -0,0 +1,30 @@ +@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) print::c ← (byte) 'a' + [5] call print + to:main::@1 +main::@1: scope:[main] from main + [6] (byte) print::c ← (byte) 'b' + [7] call print + to:main::@return +main::@return: scope:[main] from main::@1 + [8] return + to:@return + +(void()) print((byte) print::c) +print: scope:[print] from main main::@1 + [9] *((const byte*) SCREEN) ← (byte) print::c + to:print::@return +print::@return: scope:[print] from print + [10] return + to:@return diff --git a/src/test/ref/nomodify-4.log b/src/test/ref/nomodify-4.log new file mode 100644 index 000000000..4e27c8c55 --- /dev/null +++ b/src/test/ref/nomodify-4.log @@ -0,0 +1,336 @@ +Culled Empty Block (label) @1 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@2 + +(void()) main() +main: scope:[main] from @2 + (byte) print::c ← (byte) 'a' + call print + to:main::@1 +main::@1: scope:[main] from main + (byte) print::c ← (byte) 'b' + call print + to:main::@2 +main::@2: scope:[main] from main::@1 + to:main::@return +main::@return: scope:[main] from main::@2 + return + to:@return + +(void()) print((byte) print::c) +print: scope:[print] from main main::@1 + *((const byte*) SCREEN) ← (byte) print::c + to:print::@return +print::@return: scope:[print] from print + return + to:@return +@2: scope:[] from @begin + call main + to:@3 +@3: scope:[] from @2 + to:@end +@end: scope:[] from @3 + +SYMBOL TABLE SSA +(label) @2 +(label) @3 +(label) @begin +(label) @end +(const byte*) SCREEN = (byte*)(number) $400 +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@return +(void()) print((byte) print::c) +(label) print::@return +(byte) print::c loadstore + +Simplifying constant pointer cast (byte*) 1024 +Successful SSA optimization PassNCastSimplification +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 +Adding NOP phi() at start of main::@2 +CALL GRAPH +Calls in [] to main:2 +Calls in [main] to print:6 print:8 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +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() + +(void()) main() +main: scope:[main] from @1 + [4] (byte) print::c ← (byte) 'a' + [5] call print + to:main::@1 +main::@1: scope:[main] from main + [6] (byte) print::c ← (byte) 'b' + [7] call print + to:main::@return +main::@return: scope:[main] from main::@1 + [8] return + to:@return + +(void()) print((byte) print::c) +print: scope:[print] from main main::@1 + [9] *((const byte*) SCREEN) ← (byte) print::c + to:print::@return +print::@return: scope:[print] from print + [10] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(void()) print((byte) print::c) +(byte) print::c loadstore 3.0 + +Initial phi equivalence classes +Added variable print::c to live range equivalence class [ print::c ] +Complete equivalence classes +[ print::c ] +Allocated zp[1]:2 [ print::c ] + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// Test that a nomodify parameter works + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .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: { + // [4] (byte) print::c ← (byte) 'a' -- vbuz1=vbuc1 + lda #'a' + sta.z print.c + // [5] call print + jsr print + jmp __b1 + // main::@1 + __b1: + // [6] (byte) print::c ← (byte) 'b' -- vbuz1=vbuc1 + lda #'b' + sta.z print.c + // [7] call print + jsr print + jmp __breturn + // main::@return + __breturn: + // [8] return + rts +} + // print +print: { + .label c = 2 + // [9] *((const byte*) SCREEN) ← (byte) print::c -- _deref_pbuc1=vbuz1 + lda.z c + sta SCREEN + jmp __breturn + // print::@return + __breturn: + // [10] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] (byte) print::c ← (byte) 'a' [ print::c ] ( main:2 [ print::c ] ) always clobbers reg byte a +Statement [6] (byte) print::c ← (byte) 'b' [ print::c ] ( main:2 [ print::c ] ) always clobbers reg byte a +Statement [9] *((const byte*) SCREEN) ← (byte) print::c [ ] ( main:2::print:5 [ ] main:2::print:7 [ ] ) always clobbers reg byte a +Potential registers zp[1]:2 [ print::c ] : zp[1]:2 , + +REGISTER UPLIFT SCOPES +Uplift Scope [print] 3: zp[1]:2 [ print::c ] +Uplift Scope [main] +Uplift Scope [] + +Uplifting [print] best 62 combination zp[1]:2 [ print::c ] +Uplifting [main] best 62 combination +Uplifting [] best 62 combination +Attempting to uplift remaining variables inzp[1]:2 [ print::c ] +Uplifting [print] best 62 combination zp[1]:2 [ print::c ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test that a nomodify parameter works + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .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: { + // [4] (byte) print::c ← (byte) 'a' -- vbuz1=vbuc1 + lda #'a' + sta.z print.c + // [5] call print + jsr print + jmp __b1 + // main::@1 + __b1: + // [6] (byte) print::c ← (byte) 'b' -- vbuz1=vbuc1 + lda #'b' + sta.z print.c + // [7] call print + jsr print + jmp __breturn + // main::@return + __breturn: + // [8] return + rts +} + // print +print: { + .label c = 2 + // [9] *((const byte*) SCREEN) ← (byte) print::c -- _deref_pbuc1=vbuz1 + lda.z c + sta SCREEN + jmp __breturn + // print::@return + __breturn: + // [10] return + rts +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __bend +Removing instruction jmp __b1 +Removing instruction jmp __breturn +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 __b1: +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 __b1: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(const byte*) SCREEN = (byte*) 1024 +(void()) main() +(label) main::@1 +(label) main::@return +(void()) print((byte) print::c) +(label) print::@return +(byte) print::c loadstore zp[1]:2 3.0 + +zp[1]:2 [ print::c ] + + +FINAL ASSEMBLER +Score: 41 + + // File Comments +// Test that a nomodify parameter works + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .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: { + // print('a') + // [4] (byte) print::c ← (byte) 'a' -- vbuz1=vbuc1 + lda #'a' + sta.z print.c + // [5] call print + jsr print + // main::@1 + // print('b') + // [6] (byte) print::c ← (byte) 'b' -- vbuz1=vbuc1 + lda #'b' + sta.z print.c + // [7] call print + jsr print + // main::@return + // } + // [8] return + rts +} + // print +print: { + .label c = 2 + // *SCREEN = c + // [9] *((const byte*) SCREEN) ← (byte) print::c -- _deref_pbuc1=vbuz1 + lda.z c + sta SCREEN + // print::@return + // } + // [10] return + rts +} + // File Data + diff --git a/src/test/ref/nomodify-4.sym b/src/test/ref/nomodify-4.sym new file mode 100644 index 000000000..49c85c25d --- /dev/null +++ b/src/test/ref/nomodify-4.sym @@ -0,0 +1,12 @@ +(label) @1 +(label) @begin +(label) @end +(const byte*) SCREEN = (byte*) 1024 +(void()) main() +(label) main::@1 +(label) main::@return +(void()) print((byte) print::c) +(label) print::@return +(byte) print::c loadstore zp[1]:2 3.0 + +zp[1]:2 [ print::c ]