From 5652a11131fc4a7db82382c4e249f7f1c7260bd5 Mon Sep 17 00:00:00 2001 From: Jesper Gravgaard Date: Thu, 26 Sep 2019 14:35:02 +0200 Subject: [PATCH] Implemented memory variable data output. Initialization can still be optimized. #328 --- .../java/dk/camelot64/kickc/Compiler.java | 1 + .../kickc/model/symbols/SymbolVariable.java | 6 +- .../Pass0GenerateStatementSequence.java | 8 +- .../kickc/passes/Pass4CodeGeneration.java | 26 ++ .../dk/camelot64/kickc/test/TestPrograms.java | 6 +- src/test/kc/declared-memory-var-0.kc | 2 +- src/test/ref/declared-memory-var-0.asm | 17 +- src/test/ref/declared-memory-var-0.cfg | 25 +- src/test/ref/declared-memory-var-0.log | 294 ++++++++++-------- src/test/ref/declared-memory-var-0.sym | 5 +- 10 files changed, 223 insertions(+), 167 deletions(-) diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index 792c6ff75..2ca0630ea 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -114,6 +114,7 @@ public class Compiler { fileName = fileName.substring(0, fileName.length() - 3); } program.setFileName(fileName); + initAsmFragmentSynthesizer(); try { Path currentPath = new File(".").toPath(); diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/SymbolVariable.java b/src/main/java/dk/camelot64/kickc/model/symbols/SymbolVariable.java index 4f1438517..3783b7122 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/SymbolVariable.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/SymbolVariable.java @@ -55,12 +55,12 @@ public abstract class SymbolVariable implements Symbol { /** Strategy being used for storing and accessing the variable. The value depends on the directives memory/register/volatile/const - and on the compilers optimization decisions. * **/ - public enum StorageStrategy { REGISTER, MEMORY, CONSTANT } + public enum StorageStrategy {PHI_REGISTER, MEMORY, CONSTANT } /** The storage strategy for the variable. */ private StorageStrategy storageStrategy; @@ -82,7 +82,7 @@ public abstract class SymbolVariable implements Symbol { this.inferredType = false; this.comments = new ArrayList<>(); this.dataSegment = dataSegment; - this.storageStrategy = StorageStrategy.REGISTER; + this.storageStrategy = StorageStrategy.PHI_REGISTER; setFullName(); } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java index e86eafdf3..d00ebe7c9 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java @@ -262,7 +262,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor directives = declVarDirectives; VariableUnversioned param = new VariableUnversioned(ctx.NAME().getText(), getCurrentScope(), type, currentDataSegment); // Set initial storage strategy - param.setStorageStrategy(SymbolVariable.StorageStrategy.REGISTER); + param.setStorageStrategy(SymbolVariable.StorageStrategy.PHI_REGISTER); // Add directives addDirectives(param, type, directives, new StatementSource(ctx)); exitDeclTypes(); @@ -620,7 +620,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor scopeConstants = scope.getAllConstants(false); Set added = new LinkedHashSet<>(); + // Add all constants arrays incl. strings with data for(ConstantVar constantVar : scopeConstants) { if(hasData(constantVar)) { // Skip if already added @@ -461,6 +462,31 @@ public class Pass4CodeGeneration { added.add(asmName); } } + // Add all memory variables + Collection scopeVariables = scope.getAllVariables(false); + for(Variable variable : scopeVariables) { + if(variable.getStorageStrategy().equals(SymbolVariable.StorageStrategy.MEMORY)) { + // Skip if already added + String asmName = variable.getAsmName() == null ? variable.getLocalName() : variable.getAsmName(); + if(added.contains(asmName)) { + continue; + } + // Set segment + setCurrentSegment(variable.getDataSegment(), asm); + // Add any comments + generateComments(asm, variable.getComments()); + // Add any alignment + Integer declaredAlignment = variable.getDeclaredAlignment(); + if(declaredAlignment != null) { + String alignment = AsmFormat.getAsmNumber(declaredAlignment); + asm.addDataAlignment(alignment); + } + AsmDataChunk asmDataChunk = new AsmDataChunk(); + addChunkData(asmDataChunk, ZeroConstantValues.zeroValue(variable.getType(), getScope()), variable.getType(), scopeRef); + asmDataChunk.addToAsm(AsmFormat.asmFix(asmName), asm); + added.add(asmName); + } + } } /** diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index da99e2a1c..859aaf1fa 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -35,12 +35,10 @@ public class TestPrograms { public TestPrograms() { } - /* @Test - public void testDelcaredMemoryVar0() throws IOException, URISyntaxException { - compileAndCompare("declared-memory-var-0", log().verboseParse().verboseCreateSsa()); + public void testDeclaredMemoryVar0() throws IOException, URISyntaxException { + compileAndCompare("declared-memory-var-0", log()); } - */ /* @Test diff --git a/src/test/kc/declared-memory-var-0.kc b/src/test/kc/declared-memory-var-0.kc index 431a3bbc7..198f87789 100644 --- a/src/test/kc/declared-memory-var-0.kc +++ b/src/test/kc/declared-memory-var-0.kc @@ -1,6 +1,6 @@ // Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store) -memory char idx=0; +memory char idx; const char* SCREEN = 0x0400; diff --git a/src/test/ref/declared-memory-var-0.asm b/src/test/ref/declared-memory-var-0.asm index cab453187..4f318df92 100644 --- a/src/test/ref/declared-memory-var-0.asm +++ b/src/test/ref/declared-memory-var-0.asm @@ -1,18 +1,27 @@ // Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store) .pc = $801 "Basic" -:BasicUpstart(main) +:BasicUpstart(bbegin) .pc = $80d "Program" + .label idx_ptr = idx .label SCREEN = $400 +bbegin: + lda #0 + sta idx_ptr + jsr main + rts main: { ldx #0 - txa b1: + lda idx_ptr sta SCREEN,x - stx.z $ff + txa clc - adc.z $ff + adc idx_ptr + sta idx_ptr inx cpx #6 bne b1 + sta idx_ptr rts } + idx: .byte 0 diff --git a/src/test/ref/declared-memory-var-0.cfg b/src/test/ref/declared-memory-var-0.cfg index cce049948..e78e6c98c 100644 --- a/src/test/ref/declared-memory-var-0.cfg +++ b/src/test/ref/declared-memory-var-0.cfg @@ -1,25 +1,28 @@ @begin: scope:[] from - [0] phi() + [0] *((const byte*) idx_ptr) ← (byte) 0 to:@1 @1: scope:[] from @begin [1] phi() [2] call main + to:@2 +@2: scope:[] from @1 + [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) to:@end -@end: scope:[] from @1 - [3] phi() +@end: scope:[] from @2 + [4] phi() (void()) main() main: scope:[main] from @1 - [4] phi() + [5] phi() to:main::@1 main::@1: scope:[main] from main main::@1 - [5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) - [5] (byte) idx#5 ← phi( main/(byte) 0 main::@1/(byte) idx#2 ) - [6] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 - [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 - [8] (byte) main::i#1 ← ++ (byte) main::i#2 - [9] if((byte) main::i#1!=(byte) 6) goto main::@1 + [6] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) + [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) + [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 + [9] (byte) main::i#1 ← ++ (byte) main::i#2 + [10] if((byte) main::i#1!=(byte) 6) goto main::@1 to:main::@return main::@return: scope:[main] from main::@1 - [10] return + [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + [12] return to:@return diff --git a/src/test/ref/declared-memory-var-0.log b/src/test/ref/declared-memory-var-0.log index ce2c6b596..def3b2ee8 100644 --- a/src/test/ref/declared-memory-var-0.log +++ b/src/test/ref/declared-memory-var-0.log @@ -1,37 +1,41 @@ Culled Empty Block (label) main::@2 +Adding memory variable constant pointer (const byte*) idx_ptr +Updating memory variable reference *((const byte*) idx_ptr) +Updating memory variable reference *((const byte*) idx_ptr) +Updating memory variable reference *((const byte*) idx_ptr) +Updating memory variable reference *((const byte*) idx_ptr) +Updating memory variable reference *((const byte*) idx_ptr) +Updating memory variable reference *((const byte*) idx_ptr) +Updating memory variable reference *((const byte*) idx_ptr) +Updating memory variable reference *((const byte*) idx_ptr) CONTROL FLOW GRAPH SSA @begin: scope:[] from - (byte) idx#0 ← (byte) 0 + *((const byte*) idx_ptr) ← (number) 0 (byte*) SCREEN#0 ← ((byte*)) (number) $400 to:@1 (void()) main() main: scope:[main] from @1 - (byte) idx#1 ← (number) 0 (byte) main::i#0 ← (byte) 0 to:main::@1 main::@1: scope:[main] from main main::@1 (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) - (byte) idx#5 ← phi( main/(byte) idx#1 main::@1/(byte) idx#2 ) - *((byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 - (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 + *((byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) + *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 (byte) main::i#1 ← (byte) main::i#2 + rangenext(0,5) (bool~) main::$0 ← (byte) main::i#1 != rangelast(0,5) if((bool~) main::$0) goto main::@1 to:main::@return main::@return: scope:[main] from main::@1 - (byte) idx#6 ← phi( main::@1/(byte) idx#2 ) - (byte) idx#3 ← (byte) idx#6 + *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) return to:@return @1: scope:[] from @begin - (byte) idx#8 ← phi( @begin/(byte) idx#0 ) call main to:@2 @2: scope:[] from @1 - (byte) idx#7 ← phi( @1/(byte) idx#3 ) - (byte) idx#4 ← (byte) idx#7 + *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) to:@end @end: scope:[] from @2 @@ -43,15 +47,7 @@ SYMBOL TABLE SSA (byte*) SCREEN (byte*) SCREEN#0 (byte) idx memory -(byte) idx#0 memory -(byte) idx#1 memory -(byte) idx#2 memory -(byte) idx#3 memory -(byte) idx#4 memory -(byte) idx#5 memory -(byte) idx#6 memory -(byte) idx#7 memory -(byte) idx#8 memory +(const byte*) idx_ptr = &(byte) idx (void()) main() (bool~) main::$0 (label) main::@1 @@ -61,33 +57,23 @@ SYMBOL TABLE SSA (byte) main::i#1 (byte) main::i#2 -Adding number conversion cast (unumber) 0 in (byte) idx#1 ← (number) 0 +Adding number conversion cast (unumber) 0 in *((const byte*) idx_ptr) ← (number) 0 Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast *((const byte*) idx_ptr) ← (unumber)(number) 0 Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 -Inlining cast (byte) idx#1 ← (unumber)(number) 0 Successful SSA optimization Pass2InlineCast -Simplifying constant pointer cast (byte*) 1024 Simplifying constant integer cast 0 +Simplifying constant pointer cast (byte*) 1024 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) 0 Successful SSA optimization PassNFinalizeNumberTypeConversions -Alias (byte) idx#2 = (byte) idx#6 (byte) idx#3 -Alias (byte) idx#0 = (byte) idx#8 -Alias (byte) idx#4 = (byte) idx#7 -Successful SSA optimization Pass2AliasElimination -Identical Phi Values (byte) idx#4 (byte) idx#2 -Successful SSA optimization Pass2IdenticalPhiElimination -Simple Condition (bool~) main::$0 [9] if((byte) main::i#1!=rangelast(0,5)) goto main::@1 +Simple Condition (bool~) main::$0 [8] if((byte) main::i#1!=rangelast(0,5)) goto main::@1 Successful SSA optimization Pass2ConditionalJumpSimplification -Constant (const byte) idx#0 = 0 Constant (const byte*) SCREEN#0 = (byte*) 1024 -Constant (const byte) idx#1 = 0 Constant (const byte) main::i#0 = 0 Successful SSA optimization Pass2ConstantIdentification -Resolved ranged next value [7] main::i#1 ← ++ main::i#2 to ++ -Resolved ranged comparison value [9] if(main::i#1!=rangelast(0,5)) goto main::@1 to (number) 6 -Eliminating unused constant (const byte) idx#0 -Successful SSA optimization PassNEliminateUnusedVars +Resolved ranged next value [6] main::i#1 ← ++ main::i#2 to ++ +Resolved ranged comparison value [8] if(main::i#1!=rangelast(0,5)) goto main::@1 to (number) 6 Adding number conversion cast (unumber) 6 in if((byte) main::i#1!=(number) 6) goto main::@1 Successful SSA optimization PassNAddNumberTypeConversions Simplifying constant integer cast 6 @@ -95,76 +81,67 @@ Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) 6 Successful SSA optimization PassNFinalizeNumberTypeConversions Inlining constant with var siblings (const byte) main::i#0 -Inlining constant with var siblings (const byte) idx#1 Constant inlined main::i#0 = (byte) 0 -Constant inlined idx#1 = (byte) 0 Successful SSA optimization Pass2ConstantInlining Added new block during phi lifting main::@3(between main::@1 and main::@1) -Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 -Adding NOP phi() at start of @2 Adding NOP phi() at start of @end Adding NOP phi() at start of main CALL GRAPH Calls in [] to main:2 -Created 2 initial phi equivalence classes -Coalesced [12] idx#9 ← idx#2 +Created 1 initial phi equivalence classes Coalesced [13] main::i#3 ← main::i#1 -Coalesced down to 2 phi equivalence classes -Culled Empty Block (label) @2 +Coalesced down to 1 phi equivalence classes Culled Empty Block (label) main::@3 -Adding NOP phi() at start of @begin 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] phi() + [0] *((const byte*) idx_ptr) ← (byte) 0 to:@1 @1: scope:[] from @begin [1] phi() [2] call main + to:@2 +@2: scope:[] from @1 + [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) to:@end -@end: scope:[] from @1 - [3] phi() +@end: scope:[] from @2 + [4] phi() (void()) main() main: scope:[main] from @1 - [4] phi() + [5] phi() to:main::@1 main::@1: scope:[main] from main main::@1 - [5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) - [5] (byte) idx#5 ← phi( main/(byte) 0 main::@1/(byte) idx#2 ) - [6] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 - [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 - [8] (byte) main::i#1 ← ++ (byte) main::i#2 - [9] if((byte) main::i#1!=(byte) 6) goto main::@1 + [6] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) + [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) + [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 + [9] (byte) main::i#1 ← ++ (byte) main::i#2 + [10] if((byte) main::i#1!=(byte) 6) goto main::@1 to:main::@return main::@return: scope:[main] from main::@1 - [10] return + [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + [12] return to:@return VARIABLE REGISTER WEIGHTS (byte*) SCREEN (byte) idx memory -(byte) idx#2 memory 7.333333333333333 -(byte) idx#5 memory 16.5 (void()) main() (byte) main::i (byte) main::i#1 16.5 (byte) main::i#2 14.666666666666666 Initial phi equivalence classes -[ idx#5 idx#2 ] [ main::i#2 main::i#1 ] Complete equivalence classes -[ idx#5 idx#2 ] [ main::i#2 main::i#1 ] -Allocated zp ZP_BYTE:2 [ idx#5 idx#2 ] -Allocated zp ZP_BYTE:3 [ main::i#2 main::i#1 ] +Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] INITIAL ASM Target platform is c64basic / MOS6502X @@ -175,79 +152,95 @@ Target platform is c64basic / MOS6502X :BasicUpstart(bbegin) .pc = $80d "Program" // Global Constants & labels + .label idx_ptr = idx .label SCREEN = $400 - .label idx = 2 // @begin bbegin: + // [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta idx_ptr // [1] phi from @begin to @1 [phi:@begin->@1] b1_from_bbegin: jmp b1 // @1 b1: // [2] call main - // [4] phi from @1 to main [phi:@1->main] + // [5] phi from @1 to main [phi:@1->main] main_from_b1: jsr main - // [3] phi from @1 to @end [phi:@1->@end] -bend_from_b1: + jmp b2 + // @2 +b2: + // [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1 + lda idx_ptr + sta idx_ptr + // [4] phi from @2 to @end [phi:@2->@end] +bend_from_b2: jmp bend // @end bend: // main main: { - .label i = 3 - // [5] phi from main to main::@1 [phi:main->main::@1] + .label i = 2 + // [6] phi from main to main::@1 [phi:main->main::@1] b1_from_main: - // [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + // [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 lda #0 sta.z i - // [5] phi (byte) idx#5 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1 - lda #0 - sta.z idx jmp b1 - // [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + // [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1] b1_from_b1: - // [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy - // [5] phi (byte) idx#5 = (byte) idx#2 [phi:main::@1->main::@1#1] -- register_copy + // [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy jmp b1 // main::@1 b1: - // [6] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 -- pbuc1_derefidx_vbuz1=vbuz2 - lda.z idx + // [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) -- pbuc1_derefidx_vbuz1=_deref_pbuc2 ldy.z i + lda idx_ptr sta SCREEN,y - // [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 -- vbuz1=vbuz1_plus_vbuz2 - lda.z idx + // [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuz1 + lda idx_ptr clc adc.z i - sta.z idx - // [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + sta idx_ptr + // [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 inc.z i - // [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 + // [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 lda #6 cmp.z i bne b1_from_b1 jmp breturn // main::@return breturn: - // [10] return + // [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1 + lda idx_ptr + sta idx_ptr + // [12] return rts } // File Data + idx: .byte 0 REGISTER UPLIFT POTENTIAL REGISTERS -Statement [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 [ main::i#2 idx#2 ] ( main:2 [ main::i#2 idx#2 ] ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i#2 main::i#1 ] -Statement [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 [ main::i#2 idx#2 ] ( main:2 [ main::i#2 idx#2 ] ) always clobbers reg byte a -Potential registers zp ZP_BYTE:2 [ idx#5 idx#2 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y , -Potential registers zp ZP_BYTE:3 [ main::i#2 main::i#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , +Statement [0] *((const byte*) idx_ptr) ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a +Statement [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( [ ] ) always clobbers reg byte a +Statement [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) [ main::i#2 ] ( main:2 [ main::i#2 ] ) 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 ] +Statement [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a +Statement [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [0] *((const byte*) idx_ptr) ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a +Statement [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( [ ] ) always clobbers reg byte a +Statement [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a +Statement [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a +Statement [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( main:2 [ ] ) 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 , REGISTER UPLIFT SCOPES -Uplift Scope [main] 31.17: zp ZP_BYTE:3 [ main::i#2 main::i#1 ] -Uplift Scope [] 23.83: zp ZP_BYTE:2 [ idx#5 idx#2 ] +Uplift Scope [main] 31.17: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Uplift Scope [] -Uplifting [main] best 423 combination reg byte x [ main::i#2 main::i#1 ] -Uplifting [] best 343 combination reg byte a [ idx#5 idx#2 ] +Uplifting [main] best 428 combination reg byte x [ main::i#2 main::i#1 ] +Uplifting [] best 428 combination ASSEMBLER BEFORE OPTIMIZATION // File Comments @@ -257,93 +250,109 @@ ASSEMBLER BEFORE OPTIMIZATION :BasicUpstart(bbegin) .pc = $80d "Program" // Global Constants & labels + .label idx_ptr = idx .label SCREEN = $400 // @begin bbegin: + // [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta idx_ptr // [1] phi from @begin to @1 [phi:@begin->@1] b1_from_bbegin: jmp b1 // @1 b1: // [2] call main - // [4] phi from @1 to main [phi:@1->main] + // [5] phi from @1 to main [phi:@1->main] main_from_b1: jsr main - // [3] phi from @1 to @end [phi:@1->@end] -bend_from_b1: + jmp b2 + // @2 +b2: + // [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1 + lda idx_ptr + sta idx_ptr + // [4] phi from @2 to @end [phi:@2->@end] +bend_from_b2: jmp bend // @end bend: // main main: { - // [5] phi from main to main::@1 [phi:main->main::@1] + // [6] phi from main to main::@1 [phi:main->main::@1] b1_from_main: - // [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + // [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 ldx #0 - // [5] phi (byte) idx#5 = (byte) 0 [phi:main->main::@1#1] -- vbuaa=vbuc1 - lda #0 jmp b1 - // [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + // [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1] b1_from_b1: - // [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy - // [5] phi (byte) idx#5 = (byte) idx#2 [phi:main::@1->main::@1#1] -- register_copy + // [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy jmp b1 // main::@1 b1: - // [6] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 -- pbuc1_derefidx_vbuxx=vbuaa + // [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) -- pbuc1_derefidx_vbuxx=_deref_pbuc2 + lda idx_ptr sta SCREEN,x - // [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 -- vbuaa=vbuaa_plus_vbuxx - stx.z $ff + // [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuxx + txa clc - adc.z $ff - // [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + adc idx_ptr + sta idx_ptr + // [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx inx - // [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + // [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 cpx #6 bne b1_from_b1 jmp breturn // main::@return breturn: - // [10] return + // [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1 + lda idx_ptr + sta idx_ptr + // [12] return rts } // File Data + idx: .byte 0 ASSEMBLER OPTIMIZATIONS Removing instruction jmp b1 +Removing instruction jmp b2 Removing instruction jmp bend Removing instruction jmp b1 Removing instruction jmp breturn Succesful ASM optimization Pass5NextJumpElimination -Replacing instruction lda #0 with TXA Replacing label b1_from_b1 with b1 Removing instruction b1_from_bbegin: -Removing instruction b1: Removing instruction main_from_b1: -Removing instruction bend_from_b1: +Removing instruction bend_from_b2: Removing instruction b1_from_b1: Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction b1: +Removing instruction b2: Removing instruction bend: Removing instruction b1_from_main: Removing instruction breturn: Succesful ASM optimization Pass5UnusedLabelElimination -Updating BasicUpstart to call main directly -Removing instruction jsr main -Succesful ASM optimization Pass5SkipBegin +Adding RTS to root block +Succesful ASM optimization Pass5AddMainRts Removing instruction jmp b1 Succesful ASM optimization Pass5NextJumpElimination -Removing instruction bbegin: -Succesful ASM optimization Pass5UnusedLabelElimination +Removing instruction lda idx_ptr +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing unreachable instruction lda idx_ptr +Removing unreachable instruction sta idx_ptr +Succesful ASM optimization Pass5UnreachableCodeElimination FINAL SYMBOL TABLE (label) @1 +(label) @2 (label) @begin (label) @end (byte*) SCREEN (const byte*) SCREEN#0 SCREEN = (byte*) 1024 (byte) idx memory -(byte) idx#2 memory reg byte a 7.333333333333333 -(byte) idx#5 memory reg byte a 16.5 +(const byte*) idx_ptr idx_ptr = &(byte) idx (void()) main() (label) main::@1 (label) main::@return @@ -351,58 +360,69 @@ FINAL SYMBOL TABLE (byte) main::i#1 reg byte x 16.5 (byte) main::i#2 reg byte x 14.666666666666666 -reg byte a [ idx#5 idx#2 ] reg byte x [ main::i#2 main::i#1 ] FINAL ASSEMBLER -Score: 241 +Score: 323 // File Comments // Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store) // Upstart .pc = $801 "Basic" -:BasicUpstart(main) +:BasicUpstart(bbegin) .pc = $80d "Program" // Global Constants & labels + .label idx_ptr = idx .label SCREEN = $400 // @begin +bbegin: + // idx=0 + // [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta idx_ptr // [1] phi from @begin to @1 [phi:@begin->@1] // @1 // [2] call main - // [4] phi from @1 to main [phi:@1->main] - // [3] phi from @1 to @end [phi:@1->@end] + // [5] phi from @1 to main [phi:@1->main] + jsr main + rts + // @2 + // [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1 + // [4] phi from @2 to @end [phi:@2->@end] // @end // main main: { - // [5] phi from main to main::@1 [phi:main->main::@1] - // [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + // [6] phi from main to main::@1 [phi:main->main::@1] + // [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 ldx #0 - // [5] phi (byte) idx#5 = (byte) 0 [phi:main->main::@1#1] -- vbuaa=vbuc1 - txa - // [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] - // [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy - // [5] phi (byte) idx#5 = (byte) idx#2 [phi:main::@1->main::@1#1] -- register_copy + // [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + // [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy // main::@1 b1: // SCREEN[i] = idx - // [6] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 -- pbuc1_derefidx_vbuxx=vbuaa + // [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) -- pbuc1_derefidx_vbuxx=_deref_pbuc2 + lda idx_ptr sta SCREEN,x // idx +=i - // [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 -- vbuaa=vbuaa_plus_vbuxx - stx.z $ff + // [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuxx + txa clc - adc.z $ff + adc idx_ptr + sta idx_ptr // for( char i: 0..5 ) - // [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + // [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx inx - // [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + // [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 cpx #6 bne b1 // main::@return // } - // [10] return + // [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1 + sta idx_ptr + // [12] return rts } // File Data + idx: .byte 0 diff --git a/src/test/ref/declared-memory-var-0.sym b/src/test/ref/declared-memory-var-0.sym index 47d9a716f..6f09b7936 100644 --- a/src/test/ref/declared-memory-var-0.sym +++ b/src/test/ref/declared-memory-var-0.sym @@ -1,11 +1,11 @@ (label) @1 +(label) @2 (label) @begin (label) @end (byte*) SCREEN (const byte*) SCREEN#0 SCREEN = (byte*) 1024 (byte) idx memory -(byte) idx#2 memory reg byte a 7.333333333333333 -(byte) idx#5 memory reg byte a 16.5 +(const byte*) idx_ptr idx_ptr = &(byte) idx (void()) main() (label) main::@1 (label) main::@return @@ -13,5 +13,4 @@ (byte) main::i#1 reg byte x 16.5 (byte) main::i#2 reg byte x 14.666666666666666 -reg byte a [ idx#5 idx#2 ] reg byte x [ main::i#2 main::i#1 ]