diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java b/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java index 9855370a0..df234d431 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java @@ -3,6 +3,7 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.Comment; import dk.camelot64.kickc.model.ControlFlowBlock; import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.iterator.ProgramValueIterator; import dk.camelot64.kickc.model.operators.OperatorSizeOf; import dk.camelot64.kickc.model.operators.Operators; import dk.camelot64.kickc.model.statements.Statement; @@ -12,6 +13,7 @@ import dk.camelot64.kickc.model.symbols.VariableIntermediate; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypePointer; import dk.camelot64.kickc.model.values.ConstantRef; +import dk.camelot64.kickc.model.values.PointerDereferenceIndexed; import dk.camelot64.kickc.model.values.VariableRef; import java.util.ListIterator; @@ -41,6 +43,29 @@ public class Pass1PointerSizeofFix extends Pass1Base { } } } + + ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> { + if(programValue.get() instanceof PointerDereferenceIndexed) { + PointerDereferenceIndexed deref = (PointerDereferenceIndexed) programValue.get(); + if(deref.getPointer() instanceof VariableRef) { + VariableRef varRef = (VariableRef) deref.getPointer(); + Variable variable = getScope().getVariable(varRef); + SymbolTypePointer pointerType = (SymbolTypePointer) variable.getType(); + if(pointerType.getElementType().getSizeBytes() > 1) { + // Array-indexing into a non-byte pointer - multiply by sizeof() + getLog().append("Fixing pointer array-indexing " + deref.toString(getProgram())); + VariableIntermediate tmpVar = getScope().getScope(currentBlock.getScope()).addVariableIntermediate(); + tmpVar.setType(SymbolType.BYTE); + stmtIt.remove(); + ConstantRef sizeOfTargetType = OperatorSizeOf.getSizeOfConstantVar(getProgram().getScope(), pointerType.getElementType()); + stmtIt.add(new StatementAssignment(tmpVar.getRef(), deref.getIndex(), Operators.MULTIPLY, sizeOfTargetType, currentStmt.getSource(), Comment.NO_COMMENTS)); + stmtIt.add(currentStmt); + deref.setIndex(tmpVar.getRef()); + } + } + } + }); + return false; } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 26b3c28fc..3e85fbc2f 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -62,6 +62,11 @@ public class TestPrograms { compileAndCompare("word-array"); } + @Test + public void testWordArray0() throws IOException, URISyntaxException { + compileAndCompare("word-array-0"); + } + @Test public void testSizeofExpression() throws IOException, URISyntaxException { compileAndCompare("sizeof-expr"); diff --git a/src/test/kc/word-array-0.kc b/src/test/kc/word-array-0.kc new file mode 100644 index 000000000..647fd5ea2 --- /dev/null +++ b/src/test/kc/word-array-0.kc @@ -0,0 +1,11 @@ +// Tests a simple word array +void main() { + const byte* SCREEN = $400+6*40; + word[3] words = $0400; + word w1 = words[1]; + SCREEN[0] = w1; + word w2 = words[2]; + SCREEN[2] = w2; +} diff --git a/src/test/ref/word-array-0.asm b/src/test/ref/word-array-0.asm new file mode 100644 index 000000000..cf6ea89a0 --- /dev/null +++ b/src/test/ref/word-array-0.asm @@ -0,0 +1,28 @@ +// Tests a simple word array +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const SIZEOF_WORD = 2 +main: { + .label words = $400 + .label SCREEN = $400+6*$28 + .label w1 = 2 + .label w2 = 2 + lda words+1*SIZEOF_WORD + sta w1 + lda words+1*SIZEOF_WORD+1 + sta w1+1 + lda w1 + sta SCREEN + lda w1+1 + sta SCREEN+1 + lda words+2*SIZEOF_WORD + sta w2 + lda words+2*SIZEOF_WORD+1 + sta w2+1 + lda w2 + sta SCREEN+2 + lda w2+1 + sta SCREEN+3 + rts +} diff --git a/src/test/ref/word-array-0.cfg b/src/test/ref/word-array-0.cfg new file mode 100644 index 000000000..89b405e07 --- /dev/null +++ b/src/test/ref/word-array-0.cfg @@ -0,0 +1,24 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] (word) main::w1#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 1*(const byte) SIZEOF_WORD) + [5] (byte~) main::$2 ← < (word) main::w1#0 + [6] *((const byte*) main::SCREEN#0) ← (byte~) main::$2 + [7] (byte~) main::$3 ← > (word) main::w1#0 + [8] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$3 + [9] (word) main::w2#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 2*(const byte) SIZEOF_WORD) + [10] (byte~) main::$4 ← < (word) main::w2#0 + [11] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$4 + [12] (byte~) main::$5 ← > (word) main::w2#0 + [13] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$5 + to:main::@return +main::@return: scope:[main] from main + [14] return + to:@return diff --git a/src/test/ref/word-array-0.log b/src/test/ref/word-array-0.log new file mode 100644 index 000000000..241fa663e --- /dev/null +++ b/src/test/ref/word-array-0.log @@ -0,0 +1,414 @@ +Fixing pointer array-indexing *((word[3]) main::words + (byte/signed byte/word/signed word/dword/signed dword) 1) +Fixing pointer array-indexing *((word[3]) main::words + (byte/signed byte/word/signed word/dword/signed dword) 2) + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte/word/signed word/dword/signed dword~) main::$0 ← (byte/signed byte/word/signed word/dword/signed dword) 6 * (byte/signed byte/word/signed word/dword/signed dword) $28 + (word/signed dword/dword/signed word~) main::$1 ← (word/signed word/dword/signed dword) $400 + (byte/word/signed word/dword/signed dword~) main::$0 + (byte*) main::SCREEN#0 ← ((byte*)) (word/signed dword/dword/signed word~) main::$1 + (word[3]) main::words#0 ← ((word*)) (word/signed word/dword/signed dword) $400 + (byte) main::$6 ← (byte/signed byte/word/signed word/dword/signed dword) 1 * (const byte) SIZEOF_WORD + (word) main::w1#0 ← *((word[3]) main::words#0 + (byte) main::$6) + (byte~) main::$2 ← < (word) main::w1#0 + *((byte*) main::SCREEN#0 + (byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$2 + (byte~) main::$3 ← > (word) main::w1#0 + *((byte*) main::SCREEN#0 + (byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$3 + (byte) main::$7 ← (byte/signed byte/word/signed word/dword/signed dword) 2 * (const byte) SIZEOF_WORD + (word) main::w2#0 ← *((word[3]) main::words#0 + (byte) main::$7) + (byte~) main::$4 ← < (word) main::w2#0 + *((byte*) main::SCREEN#0 + (byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$4 + (byte~) main::$5 ← > (word) main::w2#0 + *((byte*) main::SCREEN#0 + (byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$5 + 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) SIZEOF_WORD = (byte/signed byte/word/signed word/dword/signed dword) 2 +(void()) main() +(byte/word/signed word/dword/signed dword~) main::$0 +(word/signed dword/dword/signed word~) main::$1 +(byte~) main::$2 +(byte~) main::$3 +(byte~) main::$4 +(byte~) main::$5 +(byte) main::$6 +(byte) main::$7 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(word) main::w1 +(word) main::w1#0 +(word) main::w2 +(word) main::w2#0 +(word[3]) main::words +(word[3]) main::words#0 + +Culled Empty Block (label) @2 +Successful SSA optimization Pass2CullEmptyBlocks +Constant (const byte/word/signed word/dword/signed dword) main::$0 = 6*$28 +Constant (const word[3]) main::words#0 = ((word*))$400 +Constant (const byte) main::$6 = 1*SIZEOF_WORD +Constant (const byte) main::$7 = 2*SIZEOF_WORD +Successful SSA optimization Pass2ConstantIdentification +Constant (const word/signed dword/dword/signed word) main::$1 = $400+main::$0 +Successful SSA optimization Pass2ConstantIdentification +Constant (const byte*) main::SCREEN#0 = ((byte*))main::$1 +Successful SSA optimization Pass2ConstantIdentification +Consolidated array index constant in *(main::words#0+main::$6) +Consolidated array index constant in *(main::SCREEN#0+0) +Consolidated array index constant in *(main::SCREEN#0+1) +Consolidated array index constant in *(main::words#0+main::$7) +Consolidated array index constant in *(main::SCREEN#0+2) +Consolidated array index constant in *(main::SCREEN#0+3) +Successful SSA optimization Pass2ConstantAdditionElimination +Constant inlined main::$6 = (byte/signed byte/word/signed word/dword/signed dword) 1*(const byte) SIZEOF_WORD +Constant inlined main::$1 = (word/signed word/dword/signed dword) $400+(byte/signed byte/word/signed word/dword/signed dword) 6*(byte/signed byte/word/signed word/dword/signed dword) $28 +Constant inlined main::$7 = (byte/signed byte/word/signed word/dword/signed dword) 2*(const byte) SIZEOF_WORD +Constant inlined main::$0 = (byte/signed byte/word/signed word/dword/signed dword) 6*(byte/signed byte/word/signed word/dword/signed dword) $28 +Successful SSA optimization Pass2ConstantInlining +Simplifying constant plus zero main::SCREEN#0+0 +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 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +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() +main: scope:[main] from @1 + [4] (word) main::w1#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 1*(const byte) SIZEOF_WORD) + [5] (byte~) main::$2 ← < (word) main::w1#0 + [6] *((const byte*) main::SCREEN#0) ← (byte~) main::$2 + [7] (byte~) main::$3 ← > (word) main::w1#0 + [8] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$3 + [9] (word) main::w2#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 2*(const byte) SIZEOF_WORD) + [10] (byte~) main::$4 ← < (word) main::w2#0 + [11] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$4 + [12] (byte~) main::$5 ← > (word) main::w2#0 + [13] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$5 + to:main::@return +main::@return: scope:[main] from main + [14] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte~) main::$2 4.0 +(byte~) main::$3 4.0 +(byte~) main::$4 4.0 +(byte~) main::$5 4.0 +(byte*) main::SCREEN +(word) main::w1 +(word) main::w1#0 2.0 +(word) main::w2 +(word) main::w2#0 2.0 +(word[3]) main::words + +Initial phi equivalence classes +Added variable main::w1#0 to zero page equivalence class [ main::w1#0 ] +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::w2#0 to zero page equivalence class [ main::w2#0 ] +Added variable main::$4 to zero page equivalence class [ main::$4 ] +Added variable main::$5 to zero page equivalence class [ main::$5 ] +Complete equivalence classes +[ main::w1#0 ] +[ main::$2 ] +[ main::$3 ] +[ main::w2#0 ] +[ main::$4 ] +[ main::$5 ] +Allocated zp ZP_WORD:2 [ main::w1#0 ] +Allocated zp ZP_BYTE:4 [ main::$2 ] +Allocated zp ZP_BYTE:5 [ main::$3 ] +Allocated zp ZP_WORD:6 [ main::w2#0 ] +Allocated zp ZP_BYTE:8 [ main::$4 ] +Allocated zp ZP_BYTE:9 [ main::$5 ] + +INITIAL ASM +//SEG0 File Comments +// Tests a simple word array +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const SIZEOF_WORD = 2 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label words = $400 + .label SCREEN = $400+6*$28 + .label _2 = 4 + .label _3 = 5 + .label _4 = 8 + .label _5 = 9 + .label w1 = 2 + .label w2 = 6 + //SEG10 [4] (word) main::w1#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 1*(const byte) SIZEOF_WORD) -- vwuz1=_deref_pwuc1 + lda words+1*SIZEOF_WORD + sta w1 + lda words+1*SIZEOF_WORD+1 + sta w1+1 + //SEG11 [5] (byte~) main::$2 ← < (word) main::w1#0 -- vbuz1=_lo_vwuz2 + lda w1 + sta _2 + //SEG12 [6] *((const byte*) main::SCREEN#0) ← (byte~) main::$2 -- _deref_pbuc1=vbuz1 + lda _2 + sta SCREEN + //SEG13 [7] (byte~) main::$3 ← > (word) main::w1#0 -- vbuz1=_hi_vwuz2 + lda w1+1 + sta _3 + //SEG14 [8] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$3 -- _deref_pbuc1=vbuz1 + lda _3 + sta SCREEN+1 + //SEG15 [9] (word) main::w2#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 2*(const byte) SIZEOF_WORD) -- vwuz1=_deref_pwuc1 + lda words+2*SIZEOF_WORD + sta w2 + lda words+2*SIZEOF_WORD+1 + sta w2+1 + //SEG16 [10] (byte~) main::$4 ← < (word) main::w2#0 -- vbuz1=_lo_vwuz2 + lda w2 + sta _4 + //SEG17 [11] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$4 -- _deref_pbuc1=vbuz1 + lda _4 + sta SCREEN+2 + //SEG18 [12] (byte~) main::$5 ← > (word) main::w2#0 -- vbuz1=_hi_vwuz2 + lda w2+1 + sta _5 + //SEG19 [13] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$5 -- _deref_pbuc1=vbuz1 + lda _5 + sta SCREEN+3 + jmp breturn + //SEG20 main::@return + breturn: + //SEG21 [14] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] (word) main::w1#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 1*(const byte) SIZEOF_WORD) [ main::w1#0 ] ( main:2 [ main::w1#0 ] ) always clobbers reg byte a +Statement [5] (byte~) main::$2 ← < (word) main::w1#0 [ main::w1#0 main::$2 ] ( main:2 [ main::w1#0 main::$2 ] ) always clobbers reg byte a +Statement [7] (byte~) main::$3 ← > (word) main::w1#0 [ main::$3 ] ( main:2 [ main::$3 ] ) always clobbers reg byte a +Statement [9] (word) main::w2#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 2*(const byte) SIZEOF_WORD) [ main::w2#0 ] ( main:2 [ main::w2#0 ] ) always clobbers reg byte a +Statement [10] (byte~) main::$4 ← < (word) main::w2#0 [ main::w2#0 main::$4 ] ( main:2 [ main::w2#0 main::$4 ] ) always clobbers reg byte a +Statement [12] (byte~) main::$5 ← > (word) main::w2#0 [ main::$5 ] ( main:2 [ main::$5 ] ) always clobbers reg byte a +Potential registers zp ZP_WORD:2 [ main::w1#0 ] : zp ZP_WORD:2 , +Potential registers zp ZP_BYTE:4 [ main::$2 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:5 [ main::$3 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_WORD:6 [ main::w2#0 ] : zp ZP_WORD:6 , +Potential registers zp ZP_BYTE:8 [ main::$4 ] : zp ZP_BYTE:8 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:9 [ main::$5 ] : zp ZP_BYTE:9 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 4: zp ZP_BYTE:4 [ main::$2 ] 4: zp ZP_BYTE:5 [ main::$3 ] 4: zp ZP_BYTE:8 [ main::$4 ] 4: zp ZP_BYTE:9 [ main::$5 ] 2: zp ZP_WORD:2 [ main::w1#0 ] 2: zp ZP_WORD:6 [ main::w2#0 ] +Uplift Scope [] + +Uplifting [main] best 77 combination reg byte a [ main::$2 ] reg byte a [ main::$3 ] reg byte a [ main::$4 ] reg byte a [ main::$5 ] zp ZP_WORD:2 [ main::w1#0 ] zp ZP_WORD:6 [ main::w2#0 ] +Limited combination testing to 100 combinations of 256 possible. +Uplifting [] best 77 combination +Coalescing zero page register [ zp ZP_WORD:2 [ main::w1#0 ] ] with [ zp ZP_WORD:6 [ main::w2#0 ] ] + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Tests a simple word array +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const SIZEOF_WORD = 2 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label words = $400 + .label SCREEN = $400+6*$28 + .label w1 = 2 + .label w2 = 2 + //SEG10 [4] (word) main::w1#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 1*(const byte) SIZEOF_WORD) -- vwuz1=_deref_pwuc1 + lda words+1*SIZEOF_WORD + sta w1 + lda words+1*SIZEOF_WORD+1 + sta w1+1 + //SEG11 [5] (byte~) main::$2 ← < (word) main::w1#0 -- vbuaa=_lo_vwuz1 + lda w1 + //SEG12 [6] *((const byte*) main::SCREEN#0) ← (byte~) main::$2 -- _deref_pbuc1=vbuaa + sta SCREEN + //SEG13 [7] (byte~) main::$3 ← > (word) main::w1#0 -- vbuaa=_hi_vwuz1 + lda w1+1 + //SEG14 [8] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$3 -- _deref_pbuc1=vbuaa + sta SCREEN+1 + //SEG15 [9] (word) main::w2#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 2*(const byte) SIZEOF_WORD) -- vwuz1=_deref_pwuc1 + lda words+2*SIZEOF_WORD + sta w2 + lda words+2*SIZEOF_WORD+1 + sta w2+1 + //SEG16 [10] (byte~) main::$4 ← < (word) main::w2#0 -- vbuaa=_lo_vwuz1 + lda w2 + //SEG17 [11] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$4 -- _deref_pbuc1=vbuaa + sta SCREEN+2 + //SEG18 [12] (byte~) main::$5 ← > (word) main::w2#0 -- vbuaa=_hi_vwuz1 + lda w2+1 + //SEG19 [13] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$5 -- _deref_pbuc1=vbuaa + sta SCREEN+3 + jmp breturn + //SEG20 main::@return + breturn: + //SEG21 [14] return + rts +} + +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 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) SIZEOF_WORD SIZEOF_WORD = (byte/signed byte/word/signed word/dword/signed dword) 2 +(void()) main() +(byte~) main::$2 reg byte a 4.0 +(byte~) main::$3 reg byte a 4.0 +(byte~) main::$4 reg byte a 4.0 +(byte~) main::$5 reg byte a 4.0 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400+(byte/signed byte/word/signed word/dword/signed dword) 6*(byte/signed byte/word/signed word/dword/signed dword) $28 +(word) main::w1 +(word) main::w1#0 w1 zp ZP_WORD:2 2.0 +(word) main::w2 +(word) main::w2#0 w2 zp ZP_WORD:2 2.0 +(word[3]) main::words +(const word[3]) main::words#0 words = ((word*))(word/signed word/dword/signed dword) $400 + +zp ZP_WORD:2 [ main::w1#0 main::w2#0 ] +reg byte a [ main::$2 ] +reg byte a [ main::$3 ] +reg byte a [ main::$4 ] +reg byte a [ main::$5 ] + + +FINAL ASSEMBLER +Score: 62 + +//SEG0 File Comments +// Tests a simple word array +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const SIZEOF_WORD = 2 +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .label words = $400 + .label SCREEN = $400+6*$28 + .label w1 = 2 + .label w2 = 2 + //SEG10 [4] (word) main::w1#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 1*(const byte) SIZEOF_WORD) -- vwuz1=_deref_pwuc1 + lda words+1*SIZEOF_WORD + sta w1 + lda words+1*SIZEOF_WORD+1 + sta w1+1 + //SEG11 [5] (byte~) main::$2 ← < (word) main::w1#0 -- vbuaa=_lo_vwuz1 + lda w1 + //SEG12 [6] *((const byte*) main::SCREEN#0) ← (byte~) main::$2 -- _deref_pbuc1=vbuaa + sta SCREEN + //SEG13 [7] (byte~) main::$3 ← > (word) main::w1#0 -- vbuaa=_hi_vwuz1 + lda w1+1 + //SEG14 [8] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$3 -- _deref_pbuc1=vbuaa + sta SCREEN+1 + //SEG15 [9] (word) main::w2#0 ← *((const word[3]) main::words#0+(byte/signed byte/word/signed word/dword/signed dword) 2*(const byte) SIZEOF_WORD) -- vwuz1=_deref_pwuc1 + lda words+2*SIZEOF_WORD + sta w2 + lda words+2*SIZEOF_WORD+1 + sta w2+1 + //SEG16 [10] (byte~) main::$4 ← < (word) main::w2#0 -- vbuaa=_lo_vwuz1 + lda w2 + //SEG17 [11] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$4 -- _deref_pbuc1=vbuaa + sta SCREEN+2 + //SEG18 [12] (byte~) main::$5 ← > (word) main::w2#0 -- vbuaa=_hi_vwuz1 + lda w2+1 + //SEG19 [13] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte~) main::$5 -- _deref_pbuc1=vbuaa + sta SCREEN+3 + //SEG20 main::@return + //SEG21 [14] return + rts +} + diff --git a/src/test/ref/word-array-0.sym b/src/test/ref/word-array-0.sym new file mode 100644 index 000000000..ffd3a1027 --- /dev/null +++ b/src/test/ref/word-array-0.sym @@ -0,0 +1,24 @@ +(label) @1 +(label) @begin +(label) @end +(const byte) SIZEOF_WORD SIZEOF_WORD = (byte/signed byte/word/signed word/dword/signed dword) 2 +(void()) main() +(byte~) main::$2 reg byte a 4.0 +(byte~) main::$3 reg byte a 4.0 +(byte~) main::$4 reg byte a 4.0 +(byte~) main::$5 reg byte a 4.0 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400+(byte/signed byte/word/signed word/dword/signed dword) 6*(byte/signed byte/word/signed word/dword/signed dword) $28 +(word) main::w1 +(word) main::w1#0 w1 zp ZP_WORD:2 2.0 +(word) main::w2 +(word) main::w2#0 w2 zp ZP_WORD:2 2.0 +(word[3]) main::words +(const word[3]) main::words#0 words = ((word*))(word/signed word/dword/signed dword) $400 + +zp ZP_WORD:2 [ main::w1#0 main::w2#0 ] +reg byte a [ main::$2 ] +reg byte a [ main::$3 ] +reg byte a [ main::$4 ] +reg byte a [ main::$5 ] diff --git a/src/test/ref/word-array.asm b/src/test/ref/word-array.asm index 2bb06ff02..1d58ab070 100644 --- a/src/test/ref/word-array.asm +++ b/src/test/ref/word-array.asm @@ -4,23 +4,30 @@ .pc = $80d "Program" main: { .label SCREEN = $400 - .label w = 2 - ldy #0 - ldx #0 + .label w = 3 + .label idx = 2 + lda #0 + sta idx + tax b1: - lda words,x + txa + asl + tay + lda words,y sta w - lda words+1,x + lda words+1,y sta w+1 lda w + ldy idx sta SCREEN,y iny lda w+1 sta SCREEN,y iny tya - tay - iny + clc + adc #1 + sta idx inx cpx #4 bne b1 diff --git a/src/test/ref/word-array.cfg b/src/test/ref/word-array.cfg index a04dc0d35..d5037b591 100644 --- a/src/test/ref/word-array.cfg +++ b/src/test/ref/word-array.cfg @@ -13,17 +13,18 @@ main: scope:[main] from @1 main::@1: scope:[main] from main main::@1 [5] (byte) main::idx#4 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@1/(byte) main::idx#3 ) [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@1/(byte) main::i#1 ) - [6] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::i#2) - [7] (byte~) main::$0 ← < (word) main::w#0 - [8] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 - [9] (byte) main::idx#1 ← ++ (byte) main::idx#4 - [10] (byte~) main::$1 ← > (word) main::w#0 - [11] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← (byte~) main::$1 - [12] (byte) main::idx#2 ← ++ (byte) main::idx#1 - [13] (byte) main::idx#3 ← ++ (byte) main::idx#2 - [14] (byte) main::i#1 ← ++ (byte) main::i#2 - [15] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 4) goto main::@1 + [6] (byte) main::$3 ← (byte) main::i#2 << (byte/signed byte/word/signed word/dword/signed dword) 1 + [7] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::$3) + [8] (byte~) main::$0 ← < (word) main::w#0 + [9] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 + [10] (byte) main::idx#1 ← ++ (byte) main::idx#4 + [11] (byte~) main::$1 ← > (word) main::w#0 + [12] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← (byte~) main::$1 + [13] (byte) main::idx#2 ← ++ (byte) main::idx#1 + [14] (byte) main::idx#3 ← ++ (byte) main::idx#2 + [15] (byte) main::i#1 ← ++ (byte) main::i#2 + [16] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 4) goto main::@1 to:main::@return main::@return: scope:[main] from main::@1 - [16] return + [17] return to:@return diff --git a/src/test/ref/word-array.log b/src/test/ref/word-array.log index a4012323e..0bef674ca 100644 --- a/src/test/ref/word-array.log +++ b/src/test/ref/word-array.log @@ -1,3 +1,4 @@ +Fixing pointer array-indexing *((word[]) main::words + (byte) main::i) CONTROL FLOW GRAPH SSA @begin: scope:[] from @@ -11,7 +12,8 @@ main: scope:[main] from @1 main::@1: scope:[main] from main main::@1 (byte) main::idx#4 ← phi( main/(byte) main::idx#0 main::@1/(byte) main::idx#3 ) (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) - (word) main::w#0 ← *((word[]) main::words#0 + (byte) main::i#2) + (byte) main::$3 ← (byte) main::i#2 * (const byte) SIZEOF_WORD + (word) main::w#0 ← *((word[]) main::words#0 + (byte) main::$3) (byte~) main::$0 ← < (word) main::w#0 *((byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 (byte) main::idx#1 ← ++ (byte) main::idx#4 @@ -38,10 +40,12 @@ SYMBOL TABLE SSA (label) @2 (label) @begin (label) @end +(const byte) SIZEOF_WORD = (byte/signed byte/word/signed word/dword/signed dword) 2 (void()) main() (byte~) main::$0 (byte~) main::$1 (bool~) main::$2 +(byte) main::$3 (label) main::@1 (label) main::@return (byte*) main::SCREEN @@ -63,7 +67,7 @@ SYMBOL TABLE SSA Culled Empty Block (label) @2 Successful SSA optimization Pass2CullEmptyBlocks -Simple Condition (bool~) main::$2 [15] if((byte) main::i#1!=rangelast(0,3)) goto main::@1 +Simple Condition (bool~) main::$2 [16] if((byte) main::i#1!=rangelast(0,3)) goto main::@1 Successful SSA optimization Pass2ConditionalJumpSimplification Constant (const word[]) main::words#0 = { $3130, $3332, $3534, $3736 } Constant (const byte*) main::SCREEN#0 = ((byte*))$400 @@ -72,6 +76,9 @@ Constant (const byte) main::i#0 = 0 Successful SSA optimization Pass2ConstantIdentification Resolved ranged next value main::i#1 ← ++ main::i#2 to ++ Resolved ranged comparison value if(main::i#1!=rangelast(0,3)) goto main::@1 to (byte/signed byte/word/signed word/dword/signed dword) 4 +Rewriting multiplication to use shift (byte) main::$3 ← (byte) main::i#2 * (const byte) SIZEOF_WORD +Successful SSA optimization Pass2MultiplyToShiftRewriting +Successful SSA optimization PassNEliminateUnusedVars Inlining constant with var siblings (const byte) main::idx#0 Inlining constant with var siblings (const byte) main::i#0 Constant inlined main::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0 @@ -86,8 +93,8 @@ CALL GRAPH Calls in [] to main:2 Created 2 initial phi equivalence classes -Coalesced [17] main::i#3 ← main::i#1 -Coalesced [18] main::idx#5 ← main::idx#3 +Coalesced [18] main::i#3 ← main::i#1 +Coalesced [19] main::idx#5 ← main::idx#3 Coalesced down to 2 phi equivalence classes Culled Empty Block (label) main::@3 Adding NOP phi() at start of @begin @@ -111,19 +118,20 @@ main: scope:[main] from @1 main::@1: scope:[main] from main main::@1 [5] (byte) main::idx#4 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@1/(byte) main::idx#3 ) [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@1/(byte) main::i#1 ) - [6] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::i#2) - [7] (byte~) main::$0 ← < (word) main::w#0 - [8] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 - [9] (byte) main::idx#1 ← ++ (byte) main::idx#4 - [10] (byte~) main::$1 ← > (word) main::w#0 - [11] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← (byte~) main::$1 - [12] (byte) main::idx#2 ← ++ (byte) main::idx#1 - [13] (byte) main::idx#3 ← ++ (byte) main::idx#2 - [14] (byte) main::i#1 ← ++ (byte) main::i#2 - [15] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 4) goto main::@1 + [6] (byte) main::$3 ← (byte) main::i#2 << (byte/signed byte/word/signed word/dword/signed dword) 1 + [7] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::$3) + [8] (byte~) main::$0 ← < (word) main::w#0 + [9] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 + [10] (byte) main::idx#1 ← ++ (byte) main::idx#4 + [11] (byte~) main::$1 ← > (word) main::w#0 + [12] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← (byte~) main::$1 + [13] (byte) main::idx#2 ← ++ (byte) main::idx#1 + [14] (byte) main::idx#3 ← ++ (byte) main::idx#2 + [15] (byte) main::i#1 ← ++ (byte) main::i#2 + [16] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 4) goto main::@1 to:main::@return main::@return: scope:[main] from main::@1 - [16] return + [17] return to:@return @@ -131,15 +139,16 @@ VARIABLE REGISTER WEIGHTS (void()) main() (byte~) main::$0 22.0 (byte~) main::$1 22.0 +(byte) main::$3 22.0 (byte*) main::SCREEN (byte) main::i (byte) main::i#1 16.5 -(byte) main::i#2 3.666666666666667 +(byte) main::i#2 3.3000000000000003 (byte) main::idx (byte) main::idx#1 11.0 (byte) main::idx#2 22.0 (byte) main::idx#3 7.333333333333333 -(byte) main::idx#4 8.25 +(byte) main::idx#4 6.6000000000000005 (word) main::w (word) main::w#0 8.25 (word[]) main::words @@ -147,6 +156,7 @@ VARIABLE REGISTER WEIGHTS Initial phi equivalence classes [ main::i#2 main::i#1 ] [ main::idx#4 main::idx#3 ] +Added variable main::$3 to zero page equivalence class [ main::$3 ] Added variable main::w#0 to zero page equivalence class [ main::w#0 ] Added variable main::$0 to zero page equivalence class [ main::$0 ] Added variable main::idx#1 to zero page equivalence class [ main::idx#1 ] @@ -155,6 +165,7 @@ Added variable main::idx#2 to zero page equivalence class [ main::idx#2 ] Complete equivalence classes [ main::i#2 main::i#1 ] [ main::idx#4 main::idx#3 ] +[ main::$3 ] [ main::w#0 ] [ main::$0 ] [ main::idx#1 ] @@ -162,11 +173,12 @@ Complete equivalence classes [ main::idx#2 ] Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] Allocated zp ZP_BYTE:3 [ main::idx#4 main::idx#3 ] -Allocated zp ZP_WORD:4 [ main::w#0 ] -Allocated zp ZP_BYTE:6 [ main::$0 ] -Allocated zp ZP_BYTE:7 [ main::idx#1 ] -Allocated zp ZP_BYTE:8 [ main::$1 ] -Allocated zp ZP_BYTE:9 [ main::idx#2 ] +Allocated zp ZP_BYTE:4 [ main::$3 ] +Allocated zp ZP_WORD:5 [ main::w#0 ] +Allocated zp ZP_BYTE:7 [ main::$0 ] +Allocated zp ZP_BYTE:8 [ main::idx#1 ] +Allocated zp ZP_BYTE:9 [ main::$1 ] +Allocated zp ZP_BYTE:10 [ main::idx#2 ] INITIAL ASM //SEG0 File Comments @@ -195,11 +207,12 @@ bend: //SEG10 main main: { .label SCREEN = $400 - .label _0 = 6 - .label _1 = 8 - .label w = 4 - .label idx = 7 - .label idx_2 = 9 + .label _0 = 7 + .label _1 = 9 + .label _3 = 4 + .label w = 5 + .label idx = 8 + .label idx_2 = $a .label idx_3 = 3 .label i = 2 .label idx_4 = 3 @@ -219,83 +232,93 @@ main: { jmp b1 //SEG17 main::@1 b1: - //SEG18 [6] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::i#2) -- vwuz1=pwuc1_derefidx_vbuz2 - ldy i + //SEG18 [6] (byte) main::$3 ← (byte) main::i#2 << (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuz1=vbuz2_rol_1 + lda i + asl + sta _3 + //SEG19 [7] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::$3) -- vwuz1=pwuc1_derefidx_vbuz2 + ldy _3 lda words,y sta w lda words+1,y sta w+1 - //SEG19 [7] (byte~) main::$0 ← < (word) main::w#0 -- vbuz1=_lo_vwuz2 + //SEG20 [8] (byte~) main::$0 ← < (word) main::w#0 -- vbuz1=_lo_vwuz2 lda w sta _0 - //SEG20 [8] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuz2 + //SEG21 [9] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuz2 lda _0 ldy idx_4 sta SCREEN,y - //SEG21 [9] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuz1=_inc_vbuz2 + //SEG22 [10] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuz1=_inc_vbuz2 ldy idx_4 iny sty idx - //SEG22 [10] (byte~) main::$1 ← > (word) main::w#0 -- vbuz1=_hi_vwuz2 + //SEG23 [11] (byte~) main::$1 ← > (word) main::w#0 -- vbuz1=_hi_vwuz2 lda w+1 sta _1 - //SEG23 [11] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← (byte~) main::$1 -- pbuc1_derefidx_vbuz1=vbuz2 + //SEG24 [12] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← (byte~) main::$1 -- pbuc1_derefidx_vbuz1=vbuz2 lda _1 ldy idx sta SCREEN,y - //SEG24 [12] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuz1=_inc_vbuz2 + //SEG25 [13] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuz1=_inc_vbuz2 ldy idx iny sty idx_2 - //SEG25 [13] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuz1=_inc_vbuz2 + //SEG26 [14] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuz1=_inc_vbuz2 ldy idx_2 iny sty idx_3 - //SEG26 [14] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + //SEG27 [15] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 inc i - //SEG27 [15] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 4) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 + //SEG28 [16] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 4) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 lda #4 cmp i bne b1_from_b1 jmp breturn - //SEG28 main::@return + //SEG29 main::@return breturn: - //SEG29 [16] return + //SEG30 [17] return rts // Clever word array that represents C64 numbers 0-7 words: .word $3130, $3332, $3534, $3736 } REGISTER UPLIFT POTENTIAL REGISTERS -Statement [6] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::i#2) [ main::i#2 main::idx#4 main::w#0 ] ( main:2 [ main::i#2 main::idx#4 main::w#0 ] ) always clobbers reg byte a +Statement [6] (byte) main::$3 ← (byte) main::i#2 << (byte/signed byte/word/signed word/dword/signed dword) 1 [ main::i#2 main::idx#4 main::$3 ] ( main:2 [ main::i#2 main::idx#4 main::$3 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ] Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::idx#4 main::idx#3 ] -Statement [7] (byte~) main::$0 ← < (word) main::w#0 [ main::i#2 main::idx#4 main::w#0 main::$0 ] ( main:2 [ main::i#2 main::idx#4 main::w#0 main::$0 ] ) always clobbers reg byte a -Statement [10] (byte~) main::$1 ← > (word) main::w#0 [ main::i#2 main::idx#1 main::$1 ] ( main:2 [ main::i#2 main::idx#1 main::$1 ] ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:7 [ main::idx#1 ] -Statement [6] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::i#2) [ main::i#2 main::idx#4 main::w#0 ] ( main:2 [ main::i#2 main::idx#4 main::w#0 ] ) always clobbers reg byte a -Statement [7] (byte~) main::$0 ← < (word) main::w#0 [ main::i#2 main::idx#4 main::w#0 main::$0 ] ( main:2 [ main::i#2 main::idx#4 main::w#0 main::$0 ] ) always clobbers reg byte a -Statement [10] (byte~) main::$1 ← > (word) main::w#0 [ main::i#2 main::idx#1 main::$1 ] ( main:2 [ main::i#2 main::idx#1 main::$1 ] ) always clobbers reg byte a +Statement [7] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::$3) [ main::i#2 main::idx#4 main::w#0 ] ( main:2 [ main::i#2 main::idx#4 main::w#0 ] ) always clobbers reg byte a +Statement [8] (byte~) main::$0 ← < (word) main::w#0 [ main::i#2 main::idx#4 main::w#0 main::$0 ] ( main:2 [ main::i#2 main::idx#4 main::w#0 main::$0 ] ) always clobbers reg byte a +Statement [11] (byte~) main::$1 ← > (word) main::w#0 [ main::i#2 main::idx#1 main::$1 ] ( main:2 [ main::i#2 main::idx#1 main::$1 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:8 [ main::idx#1 ] +Statement [6] (byte) main::$3 ← (byte) main::i#2 << (byte/signed byte/word/signed word/dword/signed dword) 1 [ main::i#2 main::idx#4 main::$3 ] ( main:2 [ main::i#2 main::idx#4 main::$3 ] ) always clobbers reg byte a +Statement [7] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::$3) [ main::i#2 main::idx#4 main::w#0 ] ( main:2 [ main::i#2 main::idx#4 main::w#0 ] ) always clobbers reg byte a +Statement [8] (byte~) main::$0 ← < (word) main::w#0 [ main::i#2 main::idx#4 main::w#0 main::$0 ] ( main:2 [ main::i#2 main::idx#4 main::w#0 main::$0 ] ) always clobbers reg byte a +Statement [11] (byte~) main::$1 ← > (word) main::w#0 [ main::i#2 main::idx#1 main::$1 ] ( main:2 [ main::i#2 main::idx#1 main::$1 ] ) always clobbers reg byte a Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y , Potential registers zp ZP_BYTE:3 [ main::idx#4 main::idx#3 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , -Potential registers zp ZP_WORD:4 [ main::w#0 ] : zp ZP_WORD:4 , -Potential registers zp ZP_BYTE:6 [ main::$0 ] : zp ZP_BYTE:6 , reg byte a , reg byte x , reg byte y , -Potential registers zp ZP_BYTE:7 [ main::idx#1 ] : zp ZP_BYTE:7 , reg byte x , reg byte y , -Potential registers zp ZP_BYTE:8 [ main::$1 ] : zp ZP_BYTE:8 , reg byte a , reg byte x , reg byte y , -Potential registers zp ZP_BYTE:9 [ main::idx#2 ] : zp ZP_BYTE:9 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:4 [ main::$3 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_WORD:5 [ main::w#0 ] : zp ZP_WORD:5 , +Potential registers zp ZP_BYTE:7 [ main::$0 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:8 [ main::idx#1 ] : zp ZP_BYTE:8 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:9 [ main::$1 ] : zp ZP_BYTE:9 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:10 [ main::idx#2 ] : zp ZP_BYTE:10 , reg byte a , reg byte x , reg byte y , REGISTER UPLIFT SCOPES -Uplift Scope [main] 22: zp ZP_BYTE:6 [ main::$0 ] 22: zp ZP_BYTE:8 [ main::$1 ] 22: zp ZP_BYTE:9 [ main::idx#2 ] 20.17: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 15.58: zp ZP_BYTE:3 [ main::idx#4 main::idx#3 ] 11: zp ZP_BYTE:7 [ main::idx#1 ] 8.25: zp ZP_WORD:4 [ main::w#0 ] +Uplift Scope [main] 22: zp ZP_BYTE:4 [ main::$3 ] 22: zp ZP_BYTE:7 [ main::$0 ] 22: zp ZP_BYTE:9 [ main::$1 ] 22: zp ZP_BYTE:10 [ main::idx#2 ] 19.8: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 13.93: zp ZP_BYTE:3 [ main::idx#4 main::idx#3 ] 11: zp ZP_BYTE:8 [ main::idx#1 ] 8.25: zp ZP_WORD:5 [ main::w#0 ] Uplift Scope [] -Uplifting [main] best 833 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ] reg byte a [ main::idx#2 ] reg byte x [ main::i#2 main::i#1 ] zp ZP_BYTE:3 [ main::idx#4 main::idx#3 ] zp ZP_BYTE:7 [ main::idx#1 ] zp ZP_WORD:4 [ main::w#0 ] -Limited combination testing to 100 combinations of 1728 possible. -Uplifting [] best 833 combination +Uplifting [main] best 993 combination reg byte a [ main::$3 ] reg byte a [ main::$0 ] reg byte a [ main::$1 ] reg byte a [ main::idx#2 ] zp ZP_BYTE:2 [ main::i#2 main::i#1 ] zp ZP_BYTE:3 [ main::idx#4 main::idx#3 ] zp ZP_BYTE:8 [ main::idx#1 ] zp ZP_WORD:5 [ main::w#0 ] +Limited combination testing to 100 combinations of 6912 possible. +Uplifting [] best 993 combination +Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Uplifting [main] best 893 combination reg byte x [ main::i#2 main::i#1 ] Attempting to uplift remaining variables inzp ZP_BYTE:3 [ main::idx#4 main::idx#3 ] -Uplifting [main] best 713 combination reg byte y [ main::idx#4 main::idx#3 ] -Attempting to uplift remaining variables inzp ZP_BYTE:7 [ main::idx#1 ] -Uplifting [main] best 623 combination reg byte y [ main::idx#1 ] -Allocated (was zp ZP_WORD:4) zp ZP_WORD:2 [ main::w#0 ] +Uplifting [main] best 893 combination zp ZP_BYTE:3 [ main::idx#4 main::idx#3 ] +Attempting to uplift remaining variables inzp ZP_BYTE:8 [ main::idx#1 ] +Uplifting [main] best 803 combination reg byte y [ main::idx#1 ] +Allocated (was zp ZP_BYTE:3) zp ZP_BYTE:2 [ main::idx#4 main::idx#3 ] +Allocated (was zp ZP_WORD:5) zp ZP_WORD:3 [ main::w#0 ] ASSEMBLER BEFORE OPTIMIZATION //SEG0 File Comments @@ -324,11 +347,13 @@ bend: //SEG10 main main: { .label SCREEN = $400 - .label w = 2 + .label w = 3 + .label idx = 2 //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] b1_from_main: - //SEG12 [5] phi (byte) main::idx#4 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 - ldy #0 + //SEG12 [5] phi (byte) main::idx#4 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta idx //SEG13 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 ldx #0 jmp b1 @@ -339,36 +364,43 @@ main: { jmp b1 //SEG17 main::@1 b1: - //SEG18 [6] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::i#2) -- vwuz1=pwuc1_derefidx_vbuxx - lda words,x + //SEG18 [6] (byte) main::$3 ← (byte) main::i#2 << (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuxx_rol_1 + txa + asl + //SEG19 [7] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::$3) -- vwuz1=pwuc1_derefidx_vbuaa + tay + lda words,y sta w - lda words+1,x + lda words+1,y sta w+1 - //SEG19 [7] (byte~) main::$0 ← < (word) main::w#0 -- vbuaa=_lo_vwuz1 + //SEG20 [8] (byte~) main::$0 ← < (word) main::w#0 -- vbuaa=_lo_vwuz1 lda w - //SEG20 [8] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 -- pbuc1_derefidx_vbuyy=vbuaa + //SEG21 [9] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuaa + ldy idx sta SCREEN,y - //SEG21 [9] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuyy=_inc_vbuyy + //SEG22 [10] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuyy=_inc_vbuz1 + ldy idx iny - //SEG22 [10] (byte~) main::$1 ← > (word) main::w#0 -- vbuaa=_hi_vwuz1 + //SEG23 [11] (byte~) main::$1 ← > (word) main::w#0 -- vbuaa=_hi_vwuz1 lda w+1 - //SEG23 [11] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← (byte~) main::$1 -- pbuc1_derefidx_vbuyy=vbuaa + //SEG24 [12] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← (byte~) main::$1 -- pbuc1_derefidx_vbuyy=vbuaa sta SCREEN,y - //SEG24 [12] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuaa=_inc_vbuyy + //SEG25 [13] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuaa=_inc_vbuyy iny tya - //SEG25 [13] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuyy=_inc_vbuaa - tay - iny - //SEG26 [14] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + //SEG26 [14] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuz1=_inc_vbuaa + clc + adc #1 + sta idx + //SEG27 [15] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx inx - //SEG27 [15] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + //SEG28 [16] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 cpx #4 bne b1_from_b1 jmp breturn - //SEG28 main::@return + //SEG29 main::@return breturn: - //SEG29 [16] return + //SEG30 [17] return rts // Clever word array that represents C64 numbers 0-7 words: .word $3130, $3332, $3534, $3736 @@ -380,6 +412,9 @@ Removing instruction jmp bend Removing instruction jmp b1 Removing instruction jmp breturn Succesful ASM optimization Pass5NextJumpElimination +Replacing instruction ldx #0 with TAX +Removing instruction ldy idx +Succesful ASM optimization Pass5UnnecesaryLoadElimination Replacing label b1_from_b1 with b1 Removing instruction b1_from_bbegin: Removing instruction b1: @@ -406,26 +441,28 @@ FINAL SYMBOL TABLE (void()) main() (byte~) main::$0 reg byte a 22.0 (byte~) main::$1 reg byte a 22.0 +(byte) main::$3 reg byte a 22.0 (label) main::@1 (label) main::@return (byte*) main::SCREEN (const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400 (byte) main::i (byte) main::i#1 reg byte x 16.5 -(byte) main::i#2 reg byte x 3.666666666666667 +(byte) main::i#2 reg byte x 3.3000000000000003 (byte) main::idx (byte) main::idx#1 reg byte y 11.0 (byte) main::idx#2 reg byte a 22.0 -(byte) main::idx#3 reg byte y 7.333333333333333 -(byte) main::idx#4 reg byte y 8.25 +(byte) main::idx#3 idx zp ZP_BYTE:2 7.333333333333333 +(byte) main::idx#4 idx zp ZP_BYTE:2 6.6000000000000005 (word) main::w -(word) main::w#0 w zp ZP_WORD:2 8.25 +(word) main::w#0 w zp ZP_WORD:3 8.25 (word[]) main::words (const word[]) main::words#0 words = { (word/signed word/dword/signed dword) $3130, (word/signed word/dword/signed dword) $3332, (word/signed word/dword/signed dword) $3534, (word/signed word/dword/signed dword) $3736 } reg byte x [ main::i#2 main::i#1 ] -reg byte y [ main::idx#4 main::idx#3 ] -zp ZP_WORD:2 [ main::w#0 ] +zp ZP_BYTE:2 [ main::idx#4 main::idx#3 ] +reg byte a [ main::$3 ] +zp ZP_WORD:3 [ main::w#0 ] reg byte a [ main::$0 ] reg byte y [ main::idx#1 ] reg byte a [ main::$1 ] @@ -433,7 +470,7 @@ reg byte a [ main::idx#2 ] FINAL ASSEMBLER -Score: 521 +Score: 671 //SEG0 File Comments // Tests a simple word array @@ -452,45 +489,53 @@ Score: 521 //SEG10 main main: { .label SCREEN = $400 - .label w = 2 + .label w = 3 + .label idx = 2 //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] - //SEG12 [5] phi (byte) main::idx#4 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 - ldy #0 + //SEG12 [5] phi (byte) main::idx#4 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta idx //SEG13 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 - ldx #0 + tax //SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] //SEG15 [5] phi (byte) main::idx#4 = (byte) main::idx#3 [phi:main::@1->main::@1#0] -- register_copy //SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#1] -- register_copy //SEG17 main::@1 b1: - //SEG18 [6] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::i#2) -- vwuz1=pwuc1_derefidx_vbuxx - lda words,x + //SEG18 [6] (byte) main::$3 ← (byte) main::i#2 << (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuxx_rol_1 + txa + asl + //SEG19 [7] (word) main::w#0 ← *((const word[]) main::words#0 + (byte) main::$3) -- vwuz1=pwuc1_derefidx_vbuaa + tay + lda words,y sta w - lda words+1,x + lda words+1,y sta w+1 - //SEG19 [7] (byte~) main::$0 ← < (word) main::w#0 -- vbuaa=_lo_vwuz1 + //SEG20 [8] (byte~) main::$0 ← < (word) main::w#0 -- vbuaa=_lo_vwuz1 lda w - //SEG20 [8] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 -- pbuc1_derefidx_vbuyy=vbuaa + //SEG21 [9] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuaa + ldy idx sta SCREEN,y - //SEG21 [9] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuyy=_inc_vbuyy + //SEG22 [10] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuyy=_inc_vbuz1 iny - //SEG22 [10] (byte~) main::$1 ← > (word) main::w#0 -- vbuaa=_hi_vwuz1 + //SEG23 [11] (byte~) main::$1 ← > (word) main::w#0 -- vbuaa=_hi_vwuz1 lda w+1 - //SEG23 [11] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← (byte~) main::$1 -- pbuc1_derefidx_vbuyy=vbuaa + //SEG24 [12] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← (byte~) main::$1 -- pbuc1_derefidx_vbuyy=vbuaa sta SCREEN,y - //SEG24 [12] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuaa=_inc_vbuyy + //SEG25 [13] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuaa=_inc_vbuyy iny tya - //SEG25 [13] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuyy=_inc_vbuaa - tay - iny - //SEG26 [14] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + //SEG26 [14] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuz1=_inc_vbuaa + clc + adc #1 + sta idx + //SEG27 [15] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx inx - //SEG27 [15] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + //SEG28 [16] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 cpx #4 bne b1 - //SEG28 main::@return - //SEG29 [16] return + //SEG29 main::@return + //SEG30 [17] return rts // Clever word array that represents C64 numbers 0-7 words: .word $3130, $3332, $3534, $3736 diff --git a/src/test/ref/word-array.sym b/src/test/ref/word-array.sym index ccbe76c76..377783156 100644 --- a/src/test/ref/word-array.sym +++ b/src/test/ref/word-array.sym @@ -4,26 +4,28 @@ (void()) main() (byte~) main::$0 reg byte a 22.0 (byte~) main::$1 reg byte a 22.0 +(byte) main::$3 reg byte a 22.0 (label) main::@1 (label) main::@return (byte*) main::SCREEN (const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400 (byte) main::i (byte) main::i#1 reg byte x 16.5 -(byte) main::i#2 reg byte x 3.666666666666667 +(byte) main::i#2 reg byte x 3.3000000000000003 (byte) main::idx (byte) main::idx#1 reg byte y 11.0 (byte) main::idx#2 reg byte a 22.0 -(byte) main::idx#3 reg byte y 7.333333333333333 -(byte) main::idx#4 reg byte y 8.25 +(byte) main::idx#3 idx zp ZP_BYTE:2 7.333333333333333 +(byte) main::idx#4 idx zp ZP_BYTE:2 6.6000000000000005 (word) main::w -(word) main::w#0 w zp ZP_WORD:2 8.25 +(word) main::w#0 w zp ZP_WORD:3 8.25 (word[]) main::words (const word[]) main::words#0 words = { (word/signed word/dword/signed dword) $3130, (word/signed word/dword/signed dword) $3332, (word/signed word/dword/signed dword) $3534, (word/signed word/dword/signed dword) $3736 } reg byte x [ main::i#2 main::i#1 ] -reg byte y [ main::idx#4 main::idx#3 ] -zp ZP_WORD:2 [ main::w#0 ] +zp ZP_BYTE:2 [ main::idx#4 main::idx#3 ] +reg byte a [ main::$3 ] +zp ZP_WORD:3 [ main::w#0 ] reg byte a [ main::$0 ] reg byte y [ main::idx#1 ] reg byte a [ main::$1 ]