diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index a30965438..4d5b4cb8b 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -37,10 +37,14 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testPreprocessor5() throws IOException, URISyntaxException { + compileAndCompare("preprocessor-5", log()); + } @Test public void testPreprocessor4() throws IOException, URISyntaxException { - compileAndCompare("preprocessor-4", log()); + compileAndCompare("preprocessor-4"); } @Test diff --git a/src/test/kc/preprocessor-5.kc b/src/test/kc/preprocessor-5.kc new file mode 100644 index 000000000..d7540d655 --- /dev/null +++ b/src/test/kc/preprocessor-5.kc @@ -0,0 +1,15 @@ +// Test the preprocessor +// Test multi-line macro + +#define PRINTXX \ + SCREEN[idx++] = 'x'; \ + SCREEN[idx++] = 'x' + +char * SCREEN = 0x0400; +char idx = 0; + +void main() { + SCREEN[idx++] = '-'; + PRINTXX; + SCREEN[idx++] = '-'; +} \ No newline at end of file diff --git a/src/test/ref/preprocessor-5.asm b/src/test/ref/preprocessor-5.asm new file mode 100644 index 000000000..ee9484fb5 --- /dev/null +++ b/src/test/ref/preprocessor-5.asm @@ -0,0 +1,20 @@ +// Test the preprocessor +// Test multi-line macro +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label SCREEN = $400 +main: { + // SCREEN[idx++] = '-' + lda #'-' + sta SCREEN + // PRINTXX + lda #'x' + sta SCREEN+1 + sta SCREEN+2 + // SCREEN[idx++] = '-' + lda #'-' + sta SCREEN+3 + // } + rts +} diff --git a/src/test/ref/preprocessor-5.cfg b/src/test/ref/preprocessor-5.cfg new file mode 100644 index 000000000..0c0c654c7 --- /dev/null +++ b/src/test/ref/preprocessor-5.cfg @@ -0,0 +1,20 @@ +@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) ← (byte) '-' + [5] *((const byte*) SCREEN+(byte) 1) ← (byte) 'x' + [6] *((const byte*) SCREEN+(byte) 2) ← (byte) 'x' + [7] *((const byte*) SCREEN+(byte) 3) ← (byte) '-' + to:main::@return +main::@return: scope:[main] from main + [8] return + to:@return diff --git a/src/test/ref/preprocessor-5.log b/src/test/ref/preprocessor-5.log new file mode 100644 index 000000000..c34d56e76 --- /dev/null +++ b/src/test/ref/preprocessor-5.log @@ -0,0 +1,324 @@ +Identified constant variable (byte*) SCREEN + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte) idx#0 ← (byte) 0 + to:@1 + +(void()) main() +main: scope:[main] from @1 + (byte) idx#7 ← phi( @1/(byte) idx#10 ) + *((const byte*) SCREEN + (byte) idx#7) ← (byte) '-' + (byte) idx#1 ← ++ (byte) idx#7 + *((const byte*) SCREEN + (byte) idx#1) ← (byte) 'x' + (byte) idx#2 ← ++ (byte) idx#1 + *((const byte*) SCREEN + (byte) idx#2) ← (byte) 'x' + (byte) idx#3 ← ++ (byte) idx#2 + *((const byte*) SCREEN + (byte) idx#3) ← (byte) '-' + (byte) idx#4 ← ++ (byte) idx#3 + to:main::@return +main::@return: scope:[main] from main + (byte) idx#8 ← phi( main/(byte) idx#4 ) + (byte) idx#5 ← (byte) idx#8 + return + to:@return +@1: scope:[] from @begin + (byte) idx#10 ← phi( @begin/(byte) idx#0 ) + call main + to:@2 +@2: scope:[] from @1 + (byte) idx#9 ← phi( @1/(byte) idx#5 ) + (byte) idx#6 ← (byte) idx#9 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(const byte*) SCREEN = (byte*)(number) $400 +(byte) idx +(byte) idx#0 +(byte) idx#1 +(byte) idx#10 +(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() +(label) main::@return + +Simplifying constant pointer cast (byte*) 1024 +Successful SSA optimization PassNCastSimplification +Alias idx#4 = idx#8 idx#5 +Alias idx#0 = idx#10 +Alias idx#6 = idx#9 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values (byte) idx#7 (byte) idx#0 +Identical Phi Values (byte) idx#6 (byte) idx#4 +Successful SSA optimization Pass2IdenticalPhiElimination +Constant (const byte) idx#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Simplifying expression containing zero SCREEN in [2] *((const byte*) SCREEN + (const byte) idx#0) ← (byte) '-' +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused variable (byte) idx#4 and assignment [7] (byte) idx#4 ← ++ (byte) idx#3 +Successful SSA optimization PassNEliminateUnusedVars +Constant right-side identified [1] (byte) idx#1 ← ++ (const byte) idx#0 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) idx#1 = ++idx#0 +Successful SSA optimization Pass2ConstantIdentification +Constant right-side identified [2] (byte) idx#2 ← ++ (const byte) idx#1 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) idx#2 = ++idx#1 +Successful SSA optimization Pass2ConstantIdentification +Constant right-side identified [3] (byte) idx#3 ← ++ (const byte) idx#2 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) idx#3 = ++idx#2 +Successful SSA optimization Pass2ConstantIdentification +Inlining constant with different constant siblings (const byte) idx#0 +Inlining constant with different constant siblings (const byte) idx#1 +Inlining constant with different constant siblings (const byte) idx#2 +Inlining constant with different constant siblings (const byte) idx#3 +Constant inlined idx#2 = ++++(byte) 0 +Constant inlined idx#3 = ++++++(byte) 0 +Constant inlined idx#0 = (byte) 0 +Constant inlined idx#1 = ++(byte) 0 +Successful SSA optimization Pass2ConstantInlining +Consolidated array index constant in *(SCREEN+++0) +Consolidated array index constant in *(SCREEN+++++0) +Consolidated array index constant in *(SCREEN+++++++0) +Successful SSA optimization Pass2ConstantAdditionElimination +Simplifying constant integer increment ++0 +Simplifying constant integer increment ++0 +Simplifying constant integer increment ++1 +Successful SSA optimization Pass2ConstantSimplification +Simplifying constant integer increment ++1 +Simplifying constant integer increment ++2 +Successful SSA optimization Pass2ConstantSimplification +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) ← (byte) '-' + [5] *((const byte*) SCREEN+(byte) 1) ← (byte) 'x' + [6] *((const byte*) SCREEN+(byte) 2) ← (byte) 'x' + [7] *((const byte*) SCREEN+(byte) 3) ← (byte) '-' + to:main::@return +main::@return: scope:[main] from main + [8] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte) idx +(void()) main() + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// Test the preprocessor +// Test multi-line macro + // 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] *((const byte*) SCREEN) ← (byte) '-' -- _deref_pbuc1=vbuc2 + lda #'-' + sta SCREEN + // [5] *((const byte*) SCREEN+(byte) 1) ← (byte) 'x' -- _deref_pbuc1=vbuc2 + lda #'x' + sta SCREEN+1 + // [6] *((const byte*) SCREEN+(byte) 2) ← (byte) 'x' -- _deref_pbuc1=vbuc2 + lda #'x' + sta SCREEN+2 + // [7] *((const byte*) SCREEN+(byte) 3) ← (byte) '-' -- _deref_pbuc1=vbuc2 + lda #'-' + sta SCREEN+3 + jmp __breturn + // main::@return + __breturn: + // [8] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((const byte*) SCREEN) ← (byte) '-' [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [5] *((const byte*) SCREEN+(byte) 1) ← (byte) 'x' [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [6] *((const byte*) SCREEN+(byte) 2) ← (byte) 'x' [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [7] *((const byte*) SCREEN+(byte) 3) ← (byte) '-' [ ] ( main:2 [ ] { } ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 45 combination +Uplifting [] best 45 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test the preprocessor +// Test multi-line macro + // 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] *((const byte*) SCREEN) ← (byte) '-' -- _deref_pbuc1=vbuc2 + lda #'-' + sta SCREEN + // [5] *((const byte*) SCREEN+(byte) 1) ← (byte) 'x' -- _deref_pbuc1=vbuc2 + lda #'x' + sta SCREEN+1 + // [6] *((const byte*) SCREEN+(byte) 2) ← (byte) 'x' -- _deref_pbuc1=vbuc2 + lda #'x' + sta SCREEN+2 + // [7] *((const byte*) SCREEN+(byte) 3) ← (byte) '-' -- _deref_pbuc1=vbuc2 + lda #'-' + sta SCREEN+3 + jmp __breturn + // main::@return + __breturn: + // [8] return + rts +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __bend +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #'x' +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction __b1_from___bbegin: +Removing instruction __b1: +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 __bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(const byte*) SCREEN = (byte*) 1024 +(byte) idx +(void()) main() +(label) main::@return + + + +FINAL ASSEMBLER +Score: 28 + + // File Comments +// Test the preprocessor +// Test multi-line macro + // 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: { + // SCREEN[idx++] = '-' + // [4] *((const byte*) SCREEN) ← (byte) '-' -- _deref_pbuc1=vbuc2 + lda #'-' + sta SCREEN + // PRINTXX + // [5] *((const byte*) SCREEN+(byte) 1) ← (byte) 'x' -- _deref_pbuc1=vbuc2 + lda #'x' + sta SCREEN+1 + // [6] *((const byte*) SCREEN+(byte) 2) ← (byte) 'x' -- _deref_pbuc1=vbuc2 + sta SCREEN+2 + // SCREEN[idx++] = '-' + // [7] *((const byte*) SCREEN+(byte) 3) ← (byte) '-' -- _deref_pbuc1=vbuc2 + lda #'-' + sta SCREEN+3 + // main::@return + // } + // [8] return + rts +} + // File Data + diff --git a/src/test/ref/preprocessor-5.sym b/src/test/ref/preprocessor-5.sym new file mode 100644 index 000000000..1a817b3c6 --- /dev/null +++ b/src/test/ref/preprocessor-5.sym @@ -0,0 +1,8 @@ +(label) @1 +(label) @begin +(label) @end +(const byte*) SCREEN = (byte*) 1024 +(byte) idx +(void()) main() +(label) main::@return +