diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/_deref_pwuc1=vbuc2.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/_deref_pwuc1=vbuc2.asm new file mode 100644 index 000000000..e52ce1203 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/_deref_pwuc1=vbuc2.asm @@ -0,0 +1,4 @@ +lda #0 +sta {c1}+1 +lda #<{c2} +sta {c1} diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/_deref_pwuc1=vwuc2.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/_deref_pwuc1=vwuc2.asm new file mode 100644 index 000000000..e8b915e3e --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/_deref_pwuc1=vwuc2.asm @@ -0,0 +1,4 @@ +lda #<{c2} +sta {c1} +lda #>{c2} +sta {c1}+1 \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/vbuaa=_hi__deref_pwuc1.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuaa=_hi__deref_pwuc1.asm new file mode 100644 index 000000000..a836deba0 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuaa=_hi__deref_pwuc1.asm @@ -0,0 +1 @@ +lda {c1}+1 \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/vbuaa=_lo__deref_pwuc1.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuaa=_lo__deref_pwuc1.asm new file mode 100644 index 000000000..bee08251a --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuaa=_lo__deref_pwuc1.asm @@ -0,0 +1 @@ +lda {c1} \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/vbuxx=_hi__deref_pwuc1.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuxx=_hi__deref_pwuc1.asm new file mode 100644 index 000000000..82c5ff27f --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuxx=_hi__deref_pwuc1.asm @@ -0,0 +1 @@ +ldx {c1}+1 \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/vbuxx=_lo__deref_pwuc1.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuxx=_lo__deref_pwuc1.asm new file mode 100644 index 000000000..0fb1355db --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuxx=_lo__deref_pwuc1.asm @@ -0,0 +1 @@ +ldx {c1} \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/vbuyy=_hi__deref_pwuc1.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuyy=_hi__deref_pwuc1.asm new file mode 100644 index 000000000..e487fed02 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuyy=_hi__deref_pwuc1.asm @@ -0,0 +1 @@ +ldy {c1}+1 \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/vbuyy=_lo__deref_pwuc1.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuyy=_lo__deref_pwuc1.asm new file mode 100644 index 000000000..21abbc8f5 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/vbuyy=_lo__deref_pwuc1.asm @@ -0,0 +1 @@ +ldy {c1} \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java index a493b87a5..869e2217a 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java @@ -44,7 +44,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { Variable variable = getProgram().getScope().getVariable(constRef); // Weed out all variables that are affected by the address-of operator - if(isAddressOfUsed(constRef)) { + if(isAddressOfUsed(constRef, getProgram())) { constants.remove(constRef); continue; } @@ -292,8 +292,9 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { * @param var tHe variable to examine * @return true if the address-of operator is used on the variable */ - private boolean isAddressOfUsed(VariableRef var) { - for(ControlFlowBlock block : getGraph().getAllBlocks()) { + public static boolean isAddressOfUsed(VariableRef var, Program program) { + + for(ControlFlowBlock block : program.getGraph().getAllBlocks()) { for(Statement statement : block.getStatements()) { if(statement instanceof StatementAssignment) { StatementAssignment assignment = (StatementAssignment) statement; @@ -314,7 +315,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { } } } - for(ConstantVar constVar : getScope().getAllConstants(true)) { + for(ConstantVar constVar : program.getScope().getAllConstants(true)) { ConstantValue constantValue = constVar.getValue(); if(constantValue instanceof ConstantVarPointer) { ConstantVarPointer constantVarPointer = (ConstantVarPointer) constantValue; diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNEliminateUnusedVars.java b/src/main/java/dk/camelot64/kickc/passes/PassNEliminateUnusedVars.java index 9a4af9d47..2f9e19961 100644 --- a/src/main/java/dk/camelot64/kickc/passes/PassNEliminateUnusedVars.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNEliminateUnusedVars.java @@ -35,7 +35,7 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization { if(statement instanceof StatementAssignment) { StatementAssignment assignment = (StatementAssignment) statement; LValue lValue = assignment.getlValue(); - if(lValue instanceof VariableRef && referenceInfos.isUnused((VariableRef) lValue)) { + if(lValue instanceof VariableRef && referenceInfos.isUnused((VariableRef) lValue) && !Pass2ConstantIdentification.isAddressOfUsed((VariableRef) lValue, getProgram())) { getLog().append("Eliminating unused variable " + lValue.toString(getProgram()) + " and assignment " + assignment.toString(getProgram(), false)); stmtIt.remove(); Variable variable = getScope().getVariable((VariableRef) lValue); @@ -45,7 +45,7 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization { } else if(statement instanceof StatementCall) { StatementCall call = (StatementCall) statement; LValue lValue = call.getlValue(); - if(lValue instanceof VariableRef && referenceInfos.isUnused((VariableRef) lValue)) { + if(lValue instanceof VariableRef && referenceInfos.isUnused((VariableRef) lValue) && !Pass2ConstantIdentification.isAddressOfUsed((VariableRef) lValue, getProgram())) { getLog().append("Eliminating unused variable - keeping the call " + lValue.toString(getProgram())); Variable variable = getScope().getVariable((VariableRef) lValue); variable.getScope().remove(variable); @@ -58,7 +58,7 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization { while(phiVarIt.hasNext()) { StatementPhiBlock.PhiVariable phiVariable = phiVarIt.next(); VariableRef variableRef = phiVariable.getVariable(); - if(referenceInfos.isUnused(variableRef)) { + if(referenceInfos.isUnused(variableRef) && !Pass2ConstantIdentification.isAddressOfUsed(variableRef, getProgram())) { getLog().append("Eliminating unused variable - keeping the phi block " + variableRef.toString(getProgram())); Variable variable = getScope().getVariable(variableRef); variable.getScope().remove(variable); diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 61d3ae8e6..ec3d17ae7 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -44,6 +44,11 @@ public class TestPrograms { AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false); } + @Test + public void testConstWordPointer() throws IOException, URISyntaxException { + compileAndCompare("const-word-pointer"); + } + @Test public void testConstParam() throws IOException, URISyntaxException { compileAndCompare("const-param"); diff --git a/src/test/java/dk/camelot64/kickc/test/kc/const-word-pointer.kc b/src/test/java/dk/camelot64/kickc/test/kc/const-word-pointer.kc new file mode 100644 index 000000000..ef1e868e3 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/kc/const-word-pointer.kc @@ -0,0 +1,13 @@ +// Test a constant word pointers (pointing to a word placed on zeropage). +// The result when running is "CML!" on the screen. + +void main () { + byte* screen = $400; + word w = $0d03; + word* wp = &w; + screen[0] = <*wp; + screen[1] = >*wp; + *wp = $210c; + screen[2] = <*wp; + screen[3] = >*wp; +} diff --git a/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.asm b/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.asm new file mode 100644 index 000000000..7e944f4b2 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.asm @@ -0,0 +1,26 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + jsr main +main: { + .label screen = $400 + .label wp = w + .label w = 2 + lda #<$d03 + sta w + lda #>$d03 + sta w+1 + lda wp + sta screen+0 + lda wp+1 + sta screen+1 + lda #<$210c + sta wp + lda #>$210c + sta wp+1 + lda wp + sta screen+2 + lda wp+1 + sta screen+3 + rts +} diff --git a/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.cfg b/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.cfg new file mode 100644 index 000000000..e4b6a9e8f --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.cfg @@ -0,0 +1,24 @@ +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @1 + [3] phi() [ ] ( ) +main: scope:[main] from @1 + [4] (word) main::w#0 ← (word/signed word/dword/signed dword) 3331 [ ] ( main:2 [ ] ) + [5] (byte~) main::$1 ← < *((const word*) main::wp#0) [ main::$1 ] ( main:2 [ main::$1 ] ) + [6] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$1 [ ] ( main:2 [ ] ) + [7] (byte~) main::$2 ← > *((const word*) main::wp#0) [ main::$2 ] ( main:2 [ main::$2 ] ) + [8] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$2 [ ] ( main:2 [ ] ) + [9] *((const word*) main::wp#0) ← (word/signed word/dword/signed dword) 8460 [ ] ( main:2 [ ] ) + [10] (byte~) main::$3 ← < *((const word*) main::wp#0) [ main::$3 ] ( main:2 [ main::$3 ] ) + [11] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$3 [ ] ( main:2 [ ] ) + [12] (byte~) main::$4 ← > *((const word*) main::wp#0) [ main::$4 ] ( main:2 [ main::$4 ] ) + [13] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$4 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main + [14] return [ ] ( main:2 [ ] ) + to:@return diff --git a/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.log b/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.log new file mode 100644 index 000000000..a75d5452c --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.log @@ -0,0 +1,444 @@ +PARSING src/test/java/dk/camelot64/kickc/test/kc/const-word-pointer.kc +// Test a constant word pointers (pointing to a word placed on zeropage). +// The result when running is "CML!" on the screen. + +void main () { + byte* screen = $400; + word w = $0d03; + word* wp = &w; + screen[0] = <*wp; + screen[1] = >*wp; + *wp = $210c; + screen[2] = <*wp; + screen[3] = >*wp; +} + +SYMBOLS +(label) @1 +(label) @begin +(label) @end +(void()) main() +(word*~) main::$0 +(byte~) main::$1 +(byte~) main::$2 +(byte~) main::$3 +(byte~) main::$4 +(label) main::@return +(byte*) main::screen +(word) main::w +(word*) main::wp + +Promoting word/signed word/dword/signed dword to byte* in main::screen ← ((byte*)) 1024 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from + (byte*) main::screen ← ((byte*)) (word/signed word/dword/signed dword) 1024 + (word) main::w ← (word/signed word/dword/signed dword) 3331 + (word*~) main::$0 ← & (word) main::w + (word*) main::wp ← (word*~) main::$0 + (byte~) main::$1 ← < *((word*) main::wp) + *((byte*) main::screen + (byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$1 + (byte~) main::$2 ← > *((word*) main::wp) + *((byte*) main::screen + (byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$2 + *((word*) main::wp) ← (word/signed word/dword/signed dword) 8460 + (byte~) main::$3 ← < *((word*) main::wp) + *((byte*) main::screen + (byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$3 + (byte~) main::$4 ← > *((word*) main::wp) + *((byte*) main::screen + (byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$4 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +PROCEDURE MODIFY VARIABLE ANALYSIS + +Completing Phi functions... + +CONTROL FLOW GRAPH SSA WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte*) main::screen#0 ← ((byte*)) (word/signed word/dword/signed dword) 1024 + (word) main::w#0 ← (word/signed word/dword/signed dword) 3331 + (word*~) main::$0 ← & (word) main::w#0 + (word*) main::wp#0 ← (word*~) main::$0 + (byte~) main::$1 ← < *((word*) main::wp#0) + *((byte*) main::screen#0 + (byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$1 + (byte~) main::$2 ← > *((word*) main::wp#0) + *((byte*) main::screen#0 + (byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$2 + *((word*) main::wp#0) ← (word/signed word/dword/signed dword) 8460 + (byte~) main::$3 ← < *((word*) main::wp#0) + *((byte*) main::screen#0 + (byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$3 + (byte~) main::$4 ← > *((word*) main::wp#0) + *((byte*) main::screen#0 + (byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$4 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(word*~) main::$0 +(byte~) main::$1 +(byte~) main::$2 +(byte~) main::$3 +(byte~) main::$4 +(label) main::@return +(byte*) main::screen +(byte*) main::screen#0 +(word) main::w +(word) main::w#0 +(word*) main::wp +(word*) main::wp#0 + +OPTIMIZING CONTROL FLOW GRAPH +Culled Empty Block (label) @2 +Succesful SSA optimization Pass2CullEmptyBlocks +Alias (word*) main::wp#0 = (word*~) main::$0 +Succesful SSA optimization Pass2AliasElimination +Constant (const byte*) main::screen#0 = ((byte*))1024 +Constant (const word*) main::wp#0 = &main::w#0 +Succesful SSA optimization Pass2ConstantIdentification +Consolidated array index constant in *(main::screen#0+0) +Consolidated array index constant in *(main::screen#0+1) +Consolidated array index constant in *(main::screen#0+2) +Consolidated array index constant in *(main::screen#0+3) +Succesful SSA optimization Pass2ConstantAdditionElimination +OPTIMIZING CONTROL FLOW GRAPH +Block Sequence Planned @begin @1 @end main main::@return +Block Sequence Planned @begin @1 @end main main::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Propagating live ranges... +Propagating live ranges... +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Block Sequence Planned @begin @1 @end main main::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Propagating live ranges... +Propagating live ranges... + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @1 + [3] phi() [ ] ( ) +main: scope:[main] from @1 + [4] (word) main::w#0 ← (word/signed word/dword/signed dword) 3331 [ ] ( main:2 [ ] ) + [5] (byte~) main::$1 ← < *((const word*) main::wp#0) [ main::$1 ] ( main:2 [ main::$1 ] ) + [6] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$1 [ ] ( main:2 [ ] ) + [7] (byte~) main::$2 ← > *((const word*) main::wp#0) [ main::$2 ] ( main:2 [ main::$2 ] ) + [8] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$2 [ ] ( main:2 [ ] ) + [9] *((const word*) main::wp#0) ← (word/signed word/dword/signed dword) 8460 [ ] ( main:2 [ ] ) + [10] (byte~) main::$3 ← < *((const word*) main::wp#0) [ main::$3 ] ( main:2 [ main::$3 ] ) + [11] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$3 [ ] ( main:2 [ ] ) + [12] (byte~) main::$4 ← > *((const word*) main::wp#0) [ main::$4 ] ( main:2 [ main::$4 ] ) + [13] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$4 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main + [14] return [ ] ( main:2 [ ] ) + to:@return + +DOMINATORS +@begin dominated by @begin +@1 dominated by @1 @begin +@end dominated by @1 @begin @end +main dominated by @1 @begin main +main::@return dominated by main::@return @1 @begin main + +NATURAL LOOPS + +NATURAL LOOPS WITH DEPTH +Found 0 loops in scope [] +Found 0 loops in scope [main] + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte~) main::$1 4.0 +(byte~) main::$2 4.0 +(byte~) main::$3 4.0 +(byte~) main::$4 4.0 +(byte*) main::screen +(word) main::w +(word) main::w#0 20.0 +(word*) main::wp + +Initial phi equivalence classes +Added variable main::w#0 to zero page equivalence class [ main::w#0 ] +Added variable main::$1 to zero page equivalence class [ main::$1 ] +Added variable main::$2 to zero page equivalence class [ main::$2 ] +Added variable main::$3 to zero page equivalence class [ main::$3 ] +Added variable main::$4 to zero page equivalence class [ main::$4 ] +Complete equivalence classes +[ main::w#0 ] +[ main::$1 ] +[ main::$2 ] +[ main::$3 ] +[ main::$4 ] +Allocated zp ZP_WORD:2 [ main::w#0 ] +Allocated zp ZP_BYTE:4 [ main::$1 ] +Allocated zp ZP_BYTE:5 [ main::$2 ] +Allocated zp ZP_BYTE:6 [ main::$3 ] +Allocated zp ZP_BYTE:7 [ main::$4 ] + +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + .label screen = $400 + .label wp = w + .label _1 = 4 + .label _2 = 5 + .label _3 = 6 + .label _4 = 7 + .label w = 2 + //SEG9 [4] (word) main::w#0 ← (word/signed word/dword/signed dword) 3331 [ ] ( main:2 [ ] ) -- vwuz1=vwuc1 + lda #<$d03 + sta w + lda #>$d03 + sta w+1 + //SEG10 [5] (byte~) main::$1 ← < *((const word*) main::wp#0) [ main::$1 ] ( main:2 [ main::$1 ] ) -- vbuz1=_lo__deref_pwuc1 + lda wp + sta _1 + //SEG11 [6] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$1 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuz1 + lda _1 + sta screen+0 + //SEG12 [7] (byte~) main::$2 ← > *((const word*) main::wp#0) [ main::$2 ] ( main:2 [ main::$2 ] ) -- vbuz1=_hi__deref_pwuc1 + lda wp+1 + sta _2 + //SEG13 [8] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$2 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuz1 + lda _2 + sta screen+1 + //SEG14 [9] *((const word*) main::wp#0) ← (word/signed word/dword/signed dword) 8460 [ ] ( main:2 [ ] ) -- _deref_pwuc1=vwuc2 + lda #<$210c + sta wp + lda #>$210c + sta wp+1 + //SEG15 [10] (byte~) main::$3 ← < *((const word*) main::wp#0) [ main::$3 ] ( main:2 [ main::$3 ] ) -- vbuz1=_lo__deref_pwuc1 + lda wp + sta _3 + //SEG16 [11] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$3 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuz1 + lda _3 + sta screen+2 + //SEG17 [12] (byte~) main::$4 ← > *((const word*) main::wp#0) [ main::$4 ] ( main:2 [ main::$4 ] ) -- vbuz1=_hi__deref_pwuc1 + lda wp+1 + sta _4 + //SEG18 [13] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$4 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuz1 + lda _4 + sta screen+3 + jmp breturn + //SEG19 main::@return + breturn: + //SEG20 [14] return [ ] ( main:2 [ ] ) + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] (word) main::w#0 ← (word/signed word/dword/signed dword) 3331 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [9] *((const word*) main::wp#0) ← (word/signed word/dword/signed dword) 8460 [ ] ( main:2 [ ] ) always clobbers reg byte a +Potential registers zp ZP_WORD:2 [ main::w#0 ] : zp ZP_WORD:2 , +Potential registers zp ZP_BYTE:4 [ main::$1 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:5 [ main::$2 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:6 [ main::$3 ] : zp ZP_BYTE:6 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:7 [ main::$4 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 20: zp ZP_WORD:2 [ main::w#0 ] 4: zp ZP_BYTE:4 [ main::$1 ] 4: zp ZP_BYTE:5 [ main::$2 ] 4: zp ZP_BYTE:6 [ main::$3 ] 4: zp ZP_BYTE:7 [ main::$4 ] +Uplift Scope [] + +Uplifting [main] best 75 combination zp ZP_WORD:2 [ main::w#0 ] reg byte a [ main::$1 ] reg byte a [ main::$2 ] reg byte a [ main::$3 ] reg byte a [ main::$4 ] +Limited combination testing to 100 combinations of 256 possible. +Uplifting [] best 75 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + .label screen = $400 + .label wp = w + .label w = 2 + //SEG9 [4] (word) main::w#0 ← (word/signed word/dword/signed dword) 3331 [ ] ( main:2 [ ] ) -- vwuz1=vwuc1 + lda #<$d03 + sta w + lda #>$d03 + sta w+1 + //SEG10 [5] (byte~) main::$1 ← < *((const word*) main::wp#0) [ main::$1 ] ( main:2 [ main::$1 ] ) -- vbuaa=_lo__deref_pwuc1 + lda wp + //SEG11 [6] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$1 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuaa + sta screen+0 + //SEG12 [7] (byte~) main::$2 ← > *((const word*) main::wp#0) [ main::$2 ] ( main:2 [ main::$2 ] ) -- vbuaa=_hi__deref_pwuc1 + lda wp+1 + //SEG13 [8] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$2 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuaa + sta screen+1 + //SEG14 [9] *((const word*) main::wp#0) ← (word/signed word/dword/signed dword) 8460 [ ] ( main:2 [ ] ) -- _deref_pwuc1=vwuc2 + lda #<$210c + sta wp + lda #>$210c + sta wp+1 + //SEG15 [10] (byte~) main::$3 ← < *((const word*) main::wp#0) [ main::$3 ] ( main:2 [ main::$3 ] ) -- vbuaa=_lo__deref_pwuc1 + lda wp + //SEG16 [11] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$3 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuaa + sta screen+2 + //SEG17 [12] (byte~) main::$4 ← > *((const word*) main::wp#0) [ main::$4 ] ( main:2 [ main::$4 ] ) -- vbuaa=_hi__deref_pwuc1 + lda wp+1 + //SEG18 [13] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$4 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuaa + sta screen+3 + jmp breturn + //SEG19 main::@return + breturn: + //SEG20 [14] return [ ] ( main:2 [ ] ) + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +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 + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$1 reg byte a 4.0 +(byte~) main::$2 reg byte a 4.0 +(byte~) main::$3 reg byte a 4.0 +(byte~) main::$4 reg byte a 4.0 +(label) main::@return +(byte*) main::screen +(const byte*) main::screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 +(word) main::w +(word) main::w#0 w zp ZP_WORD:2 20.0 +(word*) main::wp +(const word*) main::wp#0 wp = &(word) main::w#0 + +zp ZP_WORD:2 [ main::w#0 ] +reg byte a [ main::$1 ] +reg byte a [ main::$2 ] +reg byte a [ main::$3 ] +reg byte a [ main::$4 ] + + +FINAL ASSEMBLER +Score: 66 + +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +//SEG7 @end +//SEG8 main +main: { + .label screen = $400 + .label wp = w + .label w = 2 + //SEG9 [4] (word) main::w#0 ← (word/signed word/dword/signed dword) 3331 [ ] ( main:2 [ ] ) -- vwuz1=vwuc1 + lda #<$d03 + sta w + lda #>$d03 + sta w+1 + //SEG10 [5] (byte~) main::$1 ← < *((const word*) main::wp#0) [ main::$1 ] ( main:2 [ main::$1 ] ) -- vbuaa=_lo__deref_pwuc1 + lda wp + //SEG11 [6] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$1 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuaa + sta screen+0 + //SEG12 [7] (byte~) main::$2 ← > *((const word*) main::wp#0) [ main::$2 ] ( main:2 [ main::$2 ] ) -- vbuaa=_hi__deref_pwuc1 + lda wp+1 + //SEG13 [8] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$2 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuaa + sta screen+1 + //SEG14 [9] *((const word*) main::wp#0) ← (word/signed word/dword/signed dword) 8460 [ ] ( main:2 [ ] ) -- _deref_pwuc1=vwuc2 + lda #<$210c + sta wp + lda #>$210c + sta wp+1 + //SEG15 [10] (byte~) main::$3 ← < *((const word*) main::wp#0) [ main::$3 ] ( main:2 [ main::$3 ] ) -- vbuaa=_lo__deref_pwuc1 + lda wp + //SEG16 [11] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$3 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuaa + sta screen+2 + //SEG17 [12] (byte~) main::$4 ← > *((const word*) main::wp#0) [ main::$4 ] ( main:2 [ main::$4 ] ) -- vbuaa=_hi__deref_pwuc1 + lda wp+1 + //SEG18 [13] *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$4 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuaa + sta screen+3 + //SEG19 main::@return + //SEG20 [14] return [ ] ( main:2 [ ] ) + rts +} + diff --git a/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.sym b/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.sym new file mode 100644 index 000000000..f4d503383 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/const-word-pointer.sym @@ -0,0 +1,21 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$1 reg byte a 4.0 +(byte~) main::$2 reg byte a 4.0 +(byte~) main::$3 reg byte a 4.0 +(byte~) main::$4 reg byte a 4.0 +(label) main::@return +(byte*) main::screen +(const byte*) main::screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 +(word) main::w +(word) main::w#0 w zp ZP_WORD:2 20.0 +(word*) main::wp +(const word*) main::wp#0 wp = &(word) main::w#0 + +zp ZP_WORD:2 [ main::w#0 ] +reg byte a [ main::$1 ] +reg byte a [ main::$2 ] +reg byte a [ main::$3 ] +reg byte a [ main::$4 ]