diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 1b345bc8a..6d714cac4 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -38,7 +38,12 @@ public class TestPrograms { } @Test - public void testDeclaredNotConstVar8() throws IOException, URISyntaxException { + public void testDeclaredNotConstVar1() throws IOException, URISyntaxException { + compileAndCompare("declared-notconst-var-1"); + } + + @Test + public void testDeclaredNotConstVar0() throws IOException, URISyntaxException { compileAndCompare("declared-notconst-var-0"); } diff --git a/src/test/kc/declared-notconst-var-1.kc b/src/test/kc/declared-notconst-var-1.kc new file mode 100644 index 000000000..8669c6ffe --- /dev/null +++ b/src/test/kc/declared-notconst-var-1.kc @@ -0,0 +1,11 @@ +// Tests declaring a (constant) variable as __notconst + +__notconst char size = 40; + +__notconst char* SCREEN = 0x0400; + +void main() { + for( char i=0;i$400 + sta.z SCREEN+1 + jsr main + rts +main: { + ldy #0 + __b1: + cpy.z size + bcc __b2 + rts + __b2: + lda #'*' + sta (SCREEN),y + iny + jmp __b1 +} diff --git a/src/test/ref/declared-notconst-var-1.cfg b/src/test/ref/declared-notconst-var-1.cfg new file mode 100644 index 000000000..db093ee11 --- /dev/null +++ b/src/test/ref/declared-notconst-var-1.cfg @@ -0,0 +1,26 @@ +@begin: scope:[] from + [0] (byte) size#0 ← (byte) $28 + [1] (byte*) SCREEN#0 ← (byte*) 1024 + to:@1 +@1: scope:[] from @begin + [2] phi() + [3] call main + to:@end +@end: scope:[] from @1 + [4] phi() + +(void()) main() +main: scope:[main] from @1 + [5] phi() + to:main::@1 +main::@1: scope:[main] from main main::@2 + [6] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 ) + [7] if((byte) main::i#2<(byte) size#0) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [8] return + to:@return +main::@2: scope:[main] from main::@1 + [9] *((byte*) SCREEN#0 + (byte) main::i#2) ← (byte) '*' + [10] (byte) main::i#1 ← ++ (byte) main::i#2 + to:main::@1 diff --git a/src/test/ref/declared-notconst-var-1.log b/src/test/ref/declared-notconst-var-1.log new file mode 100644 index 000000000..7fbd5ebcf --- /dev/null +++ b/src/test/ref/declared-notconst-var-1.log @@ -0,0 +1,428 @@ +Culled Empty Block (label) main::@4 +Culled Empty Block (label) main::@3 +Culled Empty Block (label) main::@5 +Culled Empty Block (label) main::@6 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte) size#0 ← (number) $28 + (byte*) SCREEN#0 ← ((byte*)) (number) $400 + to:@1 + +(void()) main() +main: scope:[main] from @1 + (byte*) SCREEN#3 ← phi( @1/(byte*) SCREEN#4 ) + (byte) size#2 ← phi( @1/(byte) size#4 ) + (byte) main::i#0 ← (number) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte*) SCREEN#2 ← phi( main/(byte*) SCREEN#3 main::@2/(byte*) SCREEN#1 ) + (byte) size#1 ← phi( main/(byte) size#2 main::@2/(byte) size#3 ) + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (bool~) main::$0 ← (byte) main::i#2 < (byte) size#1 + if((bool~) main::$0) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + (byte) size#3 ← phi( main::@1/(byte) size#1 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 ) + (byte*) SCREEN#1 ← phi( main::@1/(byte*) SCREEN#2 ) + *((byte*) SCREEN#1 + (byte) main::i#3) ← (byte) '*' + (byte) main::i#1 ← ++ (byte) main::i#3 + to:main::@1 +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + (byte*) SCREEN#4 ← phi( @begin/(byte*) SCREEN#0 ) + (byte) size#4 ← phi( @begin/(byte) size#0 ) + 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 +(byte*) SCREEN +(byte*) SCREEN#0 +(byte*) SCREEN#1 +(byte*) SCREEN#2 +(byte*) SCREEN#3 +(byte*) SCREEN#4 +(void()) main() +(bool~) main::$0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(byte) main::i#3 +(byte) size +(byte) size#0 +(byte) size#1 +(byte) size#2 +(byte) size#3 +(byte) size#4 + +Adding number conversion cast (unumber) $28 in (byte) size#0 ← (number) $28 +Adding number conversion cast (unumber) 0 in (byte) main::i#0 ← (number) 0 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte) size#0 ← (unumber)(number) $28 +Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 +Inlining cast (byte) main::i#0 ← (unumber)(number) 0 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast $28 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 0 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) $28 +Finalized unsigned number type (byte) 0 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (byte*) SCREEN#1 = (byte*) SCREEN#2 +Alias (byte) main::i#2 = (byte) main::i#3 +Alias (byte) size#1 = (byte) size#3 +Alias (byte) size#0 = (byte) size#4 +Alias (byte*) SCREEN#0 = (byte*) SCREEN#4 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values (byte) size#2 (byte) size#0 +Identical Phi Values (byte*) SCREEN#3 (byte*) SCREEN#0 +Identical Phi Values (byte) size#1 (byte) size#2 +Identical Phi Values (byte*) SCREEN#1 (byte*) SCREEN#3 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition (bool~) main::$0 [6] if((byte) main::i#2<(byte) size#0) goto main::@2 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte) main::i#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Inlining constant with var siblings (const byte) main::i#0 +Constant inlined main::i#0 = (byte) 0 +Successful SSA optimization Pass2ConstantInlining +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +CALL GRAPH +Calls in [] to main:3 + +Created 1 initial phi equivalence classes +Coalesced [12] main::i#4 ← main::i#1 +Coalesced down to 1 phi equivalence classes +Culled Empty Block (label) @2 +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] (byte) size#0 ← (byte) $28 + [1] (byte*) SCREEN#0 ← (byte*) 1024 + to:@1 +@1: scope:[] from @begin + [2] phi() + [3] call main + to:@end +@end: scope:[] from @1 + [4] phi() + +(void()) main() +main: scope:[main] from @1 + [5] phi() + to:main::@1 +main::@1: scope:[main] from main main::@2 + [6] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 ) + [7] if((byte) main::i#2<(byte) size#0) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [8] return + to:@return +main::@2: scope:[main] from main::@1 + [9] *((byte*) SCREEN#0 + (byte) main::i#2) ← (byte) '*' + [10] (byte) main::i#1 ← ++ (byte) main::i#2 + to:main::@1 + + +VARIABLE REGISTER WEIGHTS +(byte*) SCREEN +(byte*) SCREEN#0 1.8571428571428572 +(void()) main() +(byte) main::i +(byte) main::i#1 22.0 +(byte) main::i#2 14.666666666666666 +(byte) size +(byte) size#0 1.625 + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +Added variable size#0 to zero page equivalence class [ size#0 ] +Added variable SCREEN#0 to zero page equivalence class [ SCREEN#0 ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ size#0 ] +[ SCREEN#0 ] +Allocated zp[1]:2 [ main::i#2 main::i#1 ] +Allocated zp[1]:3 [ size#0 ] +Allocated zp[2]:4 [ SCREEN#0 ] + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// Tests declaring a (constant) variable as __notconst + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label size = 3 + .label SCREEN = 4 + // @begin +__bbegin: + // [0] (byte) size#0 ← (byte) $28 -- vbuz1=vbuc1 + lda #$28 + sta.z size + // [1] (byte*) SCREEN#0 ← (byte*) 1024 -- pbuz1=pbuc1 + lda #<$400 + sta.z SCREEN + lda #>$400 + sta.z SCREEN+1 + // [2] phi from @begin to @1 [phi:@begin->@1] +__b1_from___bbegin: + jmp __b1 + // @1 +__b1: + // [3] call main + // [5] phi from @1 to main [phi:@1->main] +main_from___b1: + jsr main + // [4] phi from @1 to @end [phi:@1->@end] +__bend_from___b1: + jmp __bend + // @end +__bend: + // main +main: { + .label i = 2 + // [6] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta.z i + jmp __b1 + // main::@1 + __b1: + // [7] if((byte) main::i#2<(byte) size#0) goto main::@2 -- vbuz1_lt_vbuz2_then_la1 + lda.z i + cmp.z size + bcc __b2 + jmp __breturn + // main::@return + __breturn: + // [8] return + rts + // main::@2 + __b2: + // [9] *((byte*) SCREEN#0 + (byte) main::i#2) ← (byte) '*' -- pbuz1_derefidx_vbuz2=vbuc1 + lda #'*' + ldy.z i + sta (SCREEN),y + // [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc.z i + // [6] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + __b1_from___b2: + // [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy + jmp __b1 +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [1] (byte*) SCREEN#0 ← (byte*) 1024 [ size#0 SCREEN#0 ] ( [ size#0 SCREEN#0 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:3 [ size#0 ] +Statement [9] *((byte*) SCREEN#0 + (byte) main::i#2) ← (byte) '*' [ size#0 SCREEN#0 main::i#2 ] ( main:3 [ size#0 SCREEN#0 main::i#2 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ] +Statement [1] (byte*) SCREEN#0 ← (byte*) 1024 [ size#0 SCREEN#0 ] ( [ size#0 SCREEN#0 ] ) always clobbers reg byte a +Statement [9] *((byte*) SCREEN#0 + (byte) main::i#2) ← (byte) '*' [ size#0 SCREEN#0 main::i#2 ] ( main:3 [ size#0 SCREEN#0 main::i#2 ] ) always clobbers reg byte a +Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y , +Potential registers zp[1]:3 [ size#0 ] : zp[1]:3 , reg byte x , reg byte y , +Potential registers zp[2]:4 [ SCREEN#0 ] : zp[2]:4 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 36.67: zp[1]:2 [ main::i#2 main::i#1 ] +Uplift Scope [] 1.86: zp[2]:4 [ SCREEN#0 ] 1.62: zp[1]:3 [ size#0 ] + +Uplifting [main] best 298 combination reg byte y [ main::i#2 main::i#1 ] +Uplifting [] best 298 combination zp[2]:4 [ SCREEN#0 ] zp[1]:3 [ size#0 ] +Attempting to uplift remaining variables inzp[1]:3 [ size#0 ] +Uplifting [] best 298 combination zp[1]:3 [ size#0 ] +Allocated (was zp[1]:3) zp[1]:2 [ size#0 ] +Allocated (was zp[2]:4) zp[2]:3 [ SCREEN#0 ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Tests declaring a (constant) variable as __notconst + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label size = 2 + .label SCREEN = 3 + // @begin +__bbegin: + // [0] (byte) size#0 ← (byte) $28 -- vbuz1=vbuc1 + lda #$28 + sta.z size + // [1] (byte*) SCREEN#0 ← (byte*) 1024 -- pbuz1=pbuc1 + lda #<$400 + sta.z SCREEN + lda #>$400 + sta.z SCREEN+1 + // [2] phi from @begin to @1 [phi:@begin->@1] +__b1_from___bbegin: + jmp __b1 + // @1 +__b1: + // [3] call main + // [5] phi from @1 to main [phi:@1->main] +main_from___b1: + jsr main + // [4] phi from @1 to @end [phi:@1->@end] +__bend_from___b1: + jmp __bend + // @end +__bend: + // main +main: { + // [6] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + jmp __b1 + // main::@1 + __b1: + // [7] if((byte) main::i#2<(byte) size#0) goto main::@2 -- vbuyy_lt_vbuz1_then_la1 + cpy.z size + bcc __b2 + jmp __breturn + // main::@return + __breturn: + // [8] return + rts + // main::@2 + __b2: + // [9] *((byte*) SCREEN#0 + (byte) main::i#2) ← (byte) '*' -- pbuz1_derefidx_vbuyy=vbuc1 + lda #'*' + sta (SCREEN),y + // [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuyy=_inc_vbuyy + iny + // [6] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + __b1_from___b2: + // [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy + jmp __b1 +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __bend +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction __b1_from___bbegin: +Removing instruction main_from___b1: +Removing instruction __bend_from___b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction __b1: +Removing instruction __bend: +Removing instruction __b1_from_main: +Removing instruction __breturn: +Removing instruction __b1_from___b2: +Succesful ASM optimization Pass5UnusedLabelElimination +Adding RTS to root block +Succesful ASM optimization Pass5AddMainRts + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(byte*) SCREEN +(byte*) SCREEN#0 SCREEN zp[2]:3 1.8571428571428572 +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::i +(byte) main::i#1 reg byte y 22.0 +(byte) main::i#2 reg byte y 14.666666666666666 +(byte) size +(byte) size#0 size zp[1]:2 1.625 + +reg byte y [ main::i#2 main::i#1 ] +zp[1]:2 [ size#0 ] +zp[2]:3 [ SCREEN#0 ] + + +FINAL ASSEMBLER +Score: 238 + + // File Comments +// Tests declaring a (constant) variable as __notconst + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label size = 2 + .label SCREEN = 3 + // @begin +__bbegin: + // size = 40 + // [0] (byte) size#0 ← (byte) $28 -- vbuz1=vbuc1 + lda #$28 + sta.z size + // SCREEN = 0x0400 + // [1] (byte*) SCREEN#0 ← (byte*) 1024 -- pbuz1=pbuc1 + lda #<$400 + sta.z SCREEN + lda #>$400 + sta.z SCREEN+1 + // [2] phi from @begin to @1 [phi:@begin->@1] + // @1 + // [3] call main + // [5] phi from @1 to main [phi:@1->main] + jsr main + rts + // [4] phi from @1 to @end [phi:@1->@end] + // @end + // main +main: { + // [6] phi from main to main::@1 [phi:main->main::@1] + // [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + // main::@1 + __b1: + // for( char i=0;imain::@1] + // [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy + jmp __b1 +} + // File Data + diff --git a/src/test/ref/declared-notconst-var-1.sym b/src/test/ref/declared-notconst-var-1.sym new file mode 100644 index 000000000..f994de01f --- /dev/null +++ b/src/test/ref/declared-notconst-var-1.sym @@ -0,0 +1,18 @@ +(label) @1 +(label) @begin +(label) @end +(byte*) SCREEN +(byte*) SCREEN#0 SCREEN zp[2]:3 1.8571428571428572 +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::i +(byte) main::i#1 reg byte y 22.0 +(byte) main::i#2 reg byte y 14.666666666666666 +(byte) size +(byte) size#0 size zp[1]:2 1.625 + +reg byte y [ main::i#2 main::i#1 ] +zp[1]:2 [ size#0 ] +zp[2]:3 [ SCREEN#0 ]