From f45ba8eb10eb80f5f42a13d6250e54ed3cbed0f0 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sat, 15 Feb 2020 09:00:57 +0100 Subject: [PATCH] Fixed early constant identification. Added test for constant initValue. --- .../Pass1EarlyConstantIdentification.java | 104 ++-- .../dk/camelot64/kickc/test/TestPrograms.java | 5 + src/test/kc/varmodel-ma_mem-4.kc | 17 + src/test/ref/varmodel-ma_mem-4.asm | 44 ++ src/test/ref/varmodel-ma_mem-4.cfg | 28 + src/test/ref/varmodel-ma_mem-4.log | 502 ++++++++++++++++++ src/test/ref/varmodel-ma_mem-4.sym | 17 + 7 files changed, 662 insertions(+), 55 deletions(-) create mode 100644 src/test/kc/varmodel-ma_mem-4.kc create mode 100644 src/test/ref/varmodel-ma_mem-4.asm create mode 100644 src/test/ref/varmodel-ma_mem-4.cfg create mode 100644 src/test/ref/varmodel-ma_mem-4.log create mode 100644 src/test/ref/varmodel-ma_mem-4.sym diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1EarlyConstantIdentification.java b/src/main/java/dk/camelot64/kickc/passes/Pass1EarlyConstantIdentification.java index 7ea899945..4e0deb85a 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1EarlyConstantIdentification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1EarlyConstantIdentification.java @@ -1,9 +1,6 @@ package dk.camelot64.kickc.passes; -import dk.camelot64.kickc.model.CompileError; -import dk.camelot64.kickc.model.ConstantNotLiteral; -import dk.camelot64.kickc.model.ControlFlowBlock; -import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.*; import dk.camelot64.kickc.model.iterator.ProgramValueIterator; import dk.camelot64.kickc.model.operators.OperatorCastPtr; import dk.camelot64.kickc.model.statements.Statement; @@ -13,15 +10,12 @@ import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.symbols.Scope; import dk.camelot64.kickc.model.symbols.StructDefinition; import dk.camelot64.kickc.model.symbols.Variable; -import dk.camelot64.kickc.model.types.SymbolType; -import dk.camelot64.kickc.model.types.SymbolTypeConversion; -import dk.camelot64.kickc.model.types.SymbolTypeInference; -import dk.camelot64.kickc.model.types.SymbolTypeIntegerFixed; +import dk.camelot64.kickc.model.types.*; import dk.camelot64.kickc.model.values.*; import dk.camelot64.kickc.passes.utils.AliasReplacer; +import dk.camelot64.kickc.passes.utils.VarAssignments; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -43,21 +37,31 @@ public class Pass1EarlyConstantIdentification extends Pass1Base { // Skip structs continue; if(!isParameter(variableRef)) { - Collection assignments = getAssignments(variable); - if(assignments.size() == 1) { - StatementLValue assignment = assignments.iterator().next(); - if(assignment instanceof StatementAssignment) { - StatementAssignment assign = (StatementAssignment) assignment; - if(assign.getrValue1() == null && assign.getOperator() == null && assign.getrValue2() instanceof ConstantValue) { + final List varAssignments = VarAssignments.get(variableRef, getGraph(), getScope()); + if(varAssignments.size() == 1) { + final VarAssignments.VarAssignment varAssignment = varAssignments.get(0); + if(varAssignment.type.equals(VarAssignments.VarAssignment.Type.STATEMENT_LVALUE)) { + final StatementLValue assignment = varAssignment.statementLValue; + if(assignment instanceof StatementAssignment) { + StatementAssignment assign = (StatementAssignment) assignment; + if(assign.getrValue1() == null && assign.getOperator() == null && assign.getrValue2() instanceof ConstantValue) { + getLog().append("Identified constant variable " + variable.toString(getProgram())); + ConstantValue constantValue = (ConstantValue) assign.getrValue2(); + convertToConst(variable, constantValue, assignment.getComments(), aliases); + removeStmt.add(assign); + } else if(assign.getrValue1() == null && assign.getOperator() instanceof OperatorCastPtr && assign.getrValue2() instanceof ConstantValue) { + getLog().append("Identified constant variable " + variable.toString(getProgram())); + ConstantValue constantValue = new ConstantCastValue(((OperatorCastPtr) assign.getOperator()).getToType(), (ConstantValue) assign.getrValue2()); + convertToConst(variable, constantValue, assignment.getComments(), aliases); + removeStmt.add(assign); + } + } + } else if(varAssignment.type.equals(VarAssignments.VarAssignment.Type.INIT_VALUE)) { + if(!(variable.getType() instanceof SymbolTypeStruct)) { + // Only assignment is the initValue getLog().append("Identified constant variable " + variable.toString(getProgram())); - ConstantValue constantValue = (ConstantValue) assign.getrValue2(); - convertToConst(variable, constantValue, assign, aliases); - removeStmt.add(assign); - } else if(assign.getrValue1() == null && assign.getOperator() instanceof OperatorCastPtr && assign.getrValue2() instanceof ConstantValue) { - getLog().append("Identified constant variable " + variable.toString(getProgram())); - ConstantValue constantValue = new ConstantCastValue(((OperatorCastPtr) assign.getOperator()).getToType(), (ConstantValue) assign.getrValue2()); - convertToConst(variable, constantValue, assign, aliases); - removeStmt.add(assign); + ConstantValue constantValue = variable.getInitValue(); + convertToConst(variable, constantValue, variable.getComments(), aliases); } } } @@ -80,7 +84,26 @@ public class Pass1EarlyConstantIdentification extends Pass1Base { * @param constantValue The constant value * @param aliases Aliases where the map from var to const is added */ - private void convertToConst(Variable variable, ConstantValue constantValue, Statement assignment, HashMap aliases) { + private void convertToConst(Variable variable, ConstantValue constantValue, List comments, HashMap aliases) { + constantValue = prepareConstantValue(variable, constantValue); + // Convert variable to constant + SymbolVariableRef variableRef = variable.getRef(); + Scope scope = variable.getScope(); + scope.remove(variable); + Variable constVar = Variable.createConstant(variable, constantValue); + constVar.getComments().addAll(comments); + SymbolVariableRef constRef = constVar.getRef(); + aliases.put(variableRef, constRef); + scope.add(constVar); + } + + /** + * Type check and potentially add cast to the constant value + * @param variable + * @param constantValue + * @return + */ + private ConstantValue prepareConstantValue(Variable variable, ConstantValue constantValue) { // Perform type checking SymbolType valueType = SymbolTypeInference.inferType(getScope(), constantValue); SymbolType variableType = variable.getType(); @@ -100,7 +123,7 @@ public class Pass1EarlyConstantIdentification extends Pass1Base { if(variableTypeInt.contains(valueInt.getInteger())) { if(constantValue instanceof ConstantInteger) { ((ConstantInteger) constantValue).setType(variableType); - } else { + } else { constantValue = new ConstantCastValue(variableType, constantValue); } typeOk = true; @@ -116,16 +139,7 @@ public class Pass1EarlyConstantIdentification extends Pass1Base { ); } } - - // Convert to constant - SymbolVariableRef variableRef = variable.getRef(); - Scope scope = variable.getScope(); - scope.remove(variable); - Variable constVar = Variable.createConstant(variable, constantValue); - constVar.getComments().addAll(assignment.getComments()); - SymbolVariableRef constRef = constVar.getRef(); - aliases.put(variableRef, constRef); - scope.add(constVar); + return constantValue; } /** @@ -146,24 +160,4 @@ public class Pass1EarlyConstantIdentification extends Pass1Base { return false; } - /** - * Find all assignments of a variable. - * - * @param variable The variable - * @return all assignments - */ - private Collection getAssignments(Variable variable) { - Collection assignments = new ArrayList<>(); - for(ControlFlowBlock block : getGraph().getAllBlocks()) { - for(Statement statement : block.getStatements()) { - if(statement instanceof StatementLValue) { - StatementLValue assignment = (StatementLValue) statement; - if(variable.getRef().equals(assignment.getlValue())) { - assignments.add(assignment); - } - } - } - } - return assignments; - } } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index d6e1ff534..ba9aea3ad 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -43,6 +43,11 @@ public class TestPrograms { compileAndCompare("ma_coalesce_problem"); } + @Test + public void testVarModelMaMem4() throws IOException, URISyntaxException { + compileAndCompare("varmodel-ma_mem-4", log()); + } + @Test public void testVarModelMaMem3() throws IOException, URISyntaxException { compileAndCompare("varmodel-ma_mem-3"); diff --git a/src/test/kc/varmodel-ma_mem-4.kc b/src/test/kc/varmodel-ma_mem-4.kc new file mode 100644 index 000000000..90702c856 --- /dev/null +++ b/src/test/kc/varmodel-ma_mem-4.kc @@ -0,0 +1,17 @@ +// Test memory model +// Constant memory variables + +#pragma var_model(ma_mem, pointer_ssa_zp) + +char* screen = 0x0400; + +char a = 'a'; + +void main() { + char b = 'b'; + for( char i: 0..5 ) { + *(screen++) = a; + *(screen++) = b; + *(screen++) = i; + } +} diff --git a/src/test/ref/varmodel-ma_mem-4.asm b/src/test/ref/varmodel-ma_mem-4.asm new file mode 100644 index 000000000..baaccca2c --- /dev/null +++ b/src/test/ref/varmodel-ma_mem-4.asm @@ -0,0 +1,44 @@ +// Test memory model +// Constant memory variables +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const a = 'a' + .label screen = 2 +main: { + .const b = 'b' + lda #0 + sta i + lda #<$400 + sta.z screen + lda #>$400 + sta.z screen+1 + __b1: + lda #a + ldy #0 + sta (screen),y + inc.z screen + bne !+ + inc.z screen+1 + !: + lda #b + ldy #0 + sta (screen),y + inc.z screen + bne !+ + inc.z screen+1 + !: + lda i + ldy #0 + sta (screen),y + inc.z screen + bne !+ + inc.z screen+1 + !: + inc i + lda #6 + cmp i + bne __b1 + rts + i: .byte 0 +} diff --git a/src/test/ref/varmodel-ma_mem-4.cfg b/src/test/ref/varmodel-ma_mem-4.cfg new file mode 100644 index 000000000..5d07c0deb --- /dev/null +++ b/src/test/ref/varmodel-ma_mem-4.cfg @@ -0,0 +1,28 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() + +(void()) main() +main: scope:[main] from @1 + [4] (byte) main::i ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + [5] (byte*) screen#6 ← phi( main/(byte*) 1024 main::@1/(byte*) screen#3 ) + [6] *((byte*) screen#6) ← (const byte) a + [7] (byte*) screen#1 ← ++ (byte*) screen#6 + [8] *((byte*) screen#1) ← (const byte) main::b + [9] (byte*) screen#2 ← ++ (byte*) screen#1 + [10] *((byte*) screen#2) ← (byte) main::i + [11] (byte*) screen#3 ← ++ (byte*) screen#2 + [12] (byte) main::i ← ++ (byte) main::i + [13] if((byte) main::i!=(byte) 6) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + [14] return + to:@return diff --git a/src/test/ref/varmodel-ma_mem-4.log b/src/test/ref/varmodel-ma_mem-4.log new file mode 100644 index 000000000..8c634da9c --- /dev/null +++ b/src/test/ref/varmodel-ma_mem-4.log @@ -0,0 +1,502 @@ +Identified constant variable (byte) a +Identified constant variable (byte) main::b +Culled Empty Block (label) main::@2 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) screen#0 ← (byte*)(number) $400 + to:@1 + +(void()) main() +main: scope:[main] from @1 + (byte*) screen#9 ← phi( @1/(byte*) screen#10 ) + (byte) main::i ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte*) screen#6 ← phi( main/(byte*) screen#9 main::@1/(byte*) screen#3 ) + *((byte*) screen#6) ← (const byte) a + (byte*) screen#1 ← ++ (byte*) screen#6 + *((byte*) screen#1) ← (const byte) main::b + (byte*) screen#2 ← ++ (byte*) screen#1 + *((byte*) screen#2) ← (byte) main::i + (byte*) screen#3 ← ++ (byte*) screen#2 + (byte) main::i ← (byte) main::i + rangenext(0,5) + (bool~) main::$0 ← (byte) main::i != rangelast(0,5) + if((bool~) main::$0) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + (byte*) screen#7 ← phi( main::@1/(byte*) screen#3 ) + (byte*) screen#4 ← (byte*) screen#7 + return + to:@return +@1: scope:[] from @begin + (byte*) screen#10 ← phi( @begin/(byte*) screen#0 ) + call main + to:@2 +@2: scope:[] from @1 + (byte*) screen#8 ← phi( @1/(byte*) screen#4 ) + (byte*) screen#5 ← (byte*) screen#8 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(const byte) a = (byte) 'a' +(void()) main() +(bool~) main::$0 +(label) main::@1 +(label) main::@return +(const byte) main::b = (byte) 'b' +(byte) main::i loadstore +(byte*) screen +(byte*) screen#0 +(byte*) screen#1 +(byte*) screen#10 +(byte*) screen#2 +(byte*) screen#3 +(byte*) screen#4 +(byte*) screen#5 +(byte*) screen#6 +(byte*) screen#7 +(byte*) screen#8 +(byte*) screen#9 + +Simplifying constant pointer cast (byte*) 1024 +Successful SSA optimization PassNCastSimplification +Alias (byte*) screen#3 = (byte*) screen#7 (byte*) screen#4 +Alias (byte*) screen#0 = (byte*) screen#10 +Alias (byte*) screen#5 = (byte*) screen#8 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values (byte*) screen#9 (byte*) screen#0 +Identical Phi Values (byte*) screen#5 (byte*) screen#3 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition (bool~) main::$0 [12] if((byte) main::i!=rangelast(0,5)) goto main::@1 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) screen#0 = (byte*) 1024 +Successful SSA optimization Pass2ConstantIdentification +Resolved ranged next value [10] main::i ← ++ main::i to ++ +Resolved ranged comparison value [12] if(main::i!=rangelast(0,5)) goto main::@1 to (number) 6 +Adding number conversion cast (unumber) 6 in if((byte) main::i!=(number) 6) goto main::@1 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant integer cast 6 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 6 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inlining constant with var siblings (const byte*) screen#0 +Constant inlined screen#0 = (byte*) 1024 +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 +CALL GRAPH +Calls in [] to main:2 + +Created 1 initial phi equivalence classes +Coalesced [16] screen#11 ← screen#3 +Coalesced down to 1 phi equivalence classes +Culled Empty Block (label) @2 +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 + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() + +(void()) main() +main: scope:[main] from @1 + [4] (byte) main::i ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + [5] (byte*) screen#6 ← phi( main/(byte*) 1024 main::@1/(byte*) screen#3 ) + [6] *((byte*) screen#6) ← (const byte) a + [7] (byte*) screen#1 ← ++ (byte*) screen#6 + [8] *((byte*) screen#1) ← (const byte) main::b + [9] (byte*) screen#2 ← ++ (byte*) screen#1 + [10] *((byte*) screen#2) ← (byte) main::i + [11] (byte*) screen#3 ← ++ (byte*) screen#2 + [12] (byte) main::i ← ++ (byte) main::i + [13] if((byte) main::i!=(byte) 6) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + [14] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte) main::i loadstore 4.6000000000000005 +(byte*) screen +(byte*) screen#1 16.5 +(byte*) screen#2 16.5 +(byte*) screen#3 7.333333333333333 +(byte*) screen#6 16.5 + +Initial phi equivalence classes +[ screen#6 screen#3 ] +Added variable main::i to live range equivalence class [ main::i ] +Added variable screen#1 to live range equivalence class [ screen#1 ] +Added variable screen#2 to live range equivalence class [ screen#2 ] +Complete equivalence classes +[ screen#6 screen#3 ] +[ main::i ] +[ screen#1 ] +[ screen#2 ] +Allocated zp[2]:2 [ screen#6 screen#3 ] +Allocated mem[1] [ main::i ] +Allocated zp[2]:4 [ screen#1 ] +Allocated zp[2]:6 [ screen#2 ] + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// Test memory model +// Constant memory variables + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .const a = 'a' + .label screen = 4 + .label screen_1 = 6 + .label screen_2 = 2 + // @begin +__bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +__b1_from___bbegin: + jmp __b1 + // @1 +__b1: + // [2] call main + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +__bend_from___b1: + jmp __bend + // @end +__bend: + // main +main: { + .const b = 'b' + // [4] (byte) main::i ← (byte) 0 -- vbum1=vbuc1 + lda #0 + sta i + // [5] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [5] phi (byte*) screen#6 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1 + lda #<$400 + sta.z screen_2 + lda #>$400 + sta.z screen_2+1 + jmp __b1 + // [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + __b1_from___b1: + // [5] phi (byte*) screen#6 = (byte*) screen#3 [phi:main::@1->main::@1#0] -- register_copy + jmp __b1 + // main::@1 + __b1: + // [6] *((byte*) screen#6) ← (const byte) a -- _deref_pbuz1=vbuc1 + lda #a + ldy #0 + sta (screen_2),y + // [7] (byte*) screen#1 ← ++ (byte*) screen#6 -- pbuz1=_inc_pbuz2 + lda.z screen_2 + clc + adc #1 + sta.z screen + lda.z screen_2+1 + adc #0 + sta.z screen+1 + // [8] *((byte*) screen#1) ← (const byte) main::b -- _deref_pbuz1=vbuc1 + lda #b + ldy #0 + sta (screen),y + // [9] (byte*) screen#2 ← ++ (byte*) screen#1 -- pbuz1=_inc_pbuz2 + lda.z screen + clc + adc #1 + sta.z screen_1 + lda.z screen+1 + adc #0 + sta.z screen_1+1 + // [10] *((byte*) screen#2) ← (byte) main::i -- _deref_pbuz1=vbum2 + lda i + ldy #0 + sta (screen_1),y + // [11] (byte*) screen#3 ← ++ (byte*) screen#2 -- pbuz1=_inc_pbuz2 + lda.z screen_1 + clc + adc #1 + sta.z screen_2 + lda.z screen_1+1 + adc #0 + sta.z screen_2+1 + // [12] (byte) main::i ← ++ (byte) main::i -- vbum1=_inc_vbum1 + inc i + // [13] if((byte) main::i!=(byte) 6) goto main::@1 -- vbum1_neq_vbuc1_then_la1 + lda #6 + cmp i + bne __b1_from___b1 + jmp __breturn + // main::@return + __breturn: + // [14] return + rts + i: .byte 0 +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] (byte) main::i ← (byte) 0 [ main::i ] ( main:2 [ main::i ] ) always clobbers reg byte a +Statement [6] *((byte*) screen#6) ← (const byte) a [ main::i screen#6 ] ( main:2 [ main::i screen#6 ] ) always clobbers reg byte a reg byte y +Statement [7] (byte*) screen#1 ← ++ (byte*) screen#6 [ main::i screen#1 ] ( main:2 [ main::i screen#1 ] ) always clobbers reg byte a +Statement [8] *((byte*) screen#1) ← (const byte) main::b [ main::i screen#1 ] ( main:2 [ main::i screen#1 ] ) always clobbers reg byte a reg byte y +Statement [9] (byte*) screen#2 ← ++ (byte*) screen#1 [ main::i screen#2 ] ( main:2 [ main::i screen#2 ] ) always clobbers reg byte a +Statement [10] *((byte*) screen#2) ← (byte) main::i [ main::i screen#2 ] ( main:2 [ main::i screen#2 ] ) always clobbers reg byte a reg byte y +Statement [11] (byte*) screen#3 ← ++ (byte*) screen#2 [ main::i screen#3 ] ( main:2 [ main::i screen#3 ] ) always clobbers reg byte a +Statement [13] if((byte) main::i!=(byte) 6) goto main::@1 [ main::i screen#3 ] ( main:2 [ main::i screen#3 ] ) always clobbers reg byte a +Potential registers zp[2]:2 [ screen#6 screen#3 ] : zp[2]:2 , +Potential registers mem[1] [ main::i ] : mem[1] , +Potential registers zp[2]:4 [ screen#1 ] : zp[2]:4 , +Potential registers zp[2]:6 [ screen#2 ] : zp[2]:6 , + +REGISTER UPLIFT SCOPES +Uplift Scope [] 23.83: zp[2]:2 [ screen#6 screen#3 ] 16.5: zp[2]:4 [ screen#1 ] 16.5: zp[2]:6 [ screen#2 ] +Uplift Scope [main] 4.6: mem[1] [ main::i ] + +Uplifting [] best 1219 combination zp[2]:2 [ screen#6 screen#3 ] zp[2]:4 [ screen#1 ] zp[2]:6 [ screen#2 ] +Uplifting [main] best 1219 combination mem[1] [ main::i ] +Attempting to uplift remaining variables inmem[1] [ main::i ] +Uplifting [main] best 1219 combination mem[1] [ main::i ] +Coalescing zero page register [ zp[2]:2 [ screen#6 screen#3 ] ] with [ zp[2]:4 [ screen#1 ] ] - score: 1 +Coalescing zero page register [ zp[2]:2 [ screen#6 screen#3 screen#1 ] ] with [ zp[2]:6 [ screen#2 ] ] - score: 1 + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test memory model +// Constant memory variables + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + .const a = 'a' + .label screen = 2 + // @begin +__bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +__b1_from___bbegin: + jmp __b1 + // @1 +__b1: + // [2] call main + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +__bend_from___b1: + jmp __bend + // @end +__bend: + // main +main: { + .const b = 'b' + // [4] (byte) main::i ← (byte) 0 -- vbum1=vbuc1 + lda #0 + sta i + // [5] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [5] phi (byte*) screen#6 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1 + lda #<$400 + sta.z screen + lda #>$400 + sta.z screen+1 + jmp __b1 + // [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + __b1_from___b1: + // [5] phi (byte*) screen#6 = (byte*) screen#3 [phi:main::@1->main::@1#0] -- register_copy + jmp __b1 + // main::@1 + __b1: + // [6] *((byte*) screen#6) ← (const byte) a -- _deref_pbuz1=vbuc1 + lda #a + ldy #0 + sta (screen),y + // [7] (byte*) screen#1 ← ++ (byte*) screen#6 -- pbuz1=_inc_pbuz1 + inc.z screen + bne !+ + inc.z screen+1 + !: + // [8] *((byte*) screen#1) ← (const byte) main::b -- _deref_pbuz1=vbuc1 + lda #b + ldy #0 + sta (screen),y + // [9] (byte*) screen#2 ← ++ (byte*) screen#1 -- pbuz1=_inc_pbuz1 + inc.z screen + bne !+ + inc.z screen+1 + !: + // [10] *((byte*) screen#2) ← (byte) main::i -- _deref_pbuz1=vbum2 + lda i + ldy #0 + sta (screen),y + // [11] (byte*) screen#3 ← ++ (byte*) screen#2 -- pbuz1=_inc_pbuz1 + inc.z screen + bne !+ + inc.z screen+1 + !: + // [12] (byte) main::i ← ++ (byte) main::i -- vbum1=_inc_vbum1 + inc i + // [13] if((byte) main::i!=(byte) 6) goto main::@1 -- vbum1_neq_vbuc1_then_la1 + lda #6 + cmp i + bne __b1_from___b1 + jmp __breturn + // main::@return + __breturn: + // [14] return + rts + i: .byte 0 +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __bend +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing label __bbegin with __b1 +Replacing label __b1_from___b1 with __b1 +Removing instruction __bbegin: +Removing instruction __b1_from___bbegin: +Removing instruction __bend_from___b1: +Removing instruction __b1_from___b1: +Succesful ASM optimization Pass5RedundantLabelElimination +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 +Removing instruction jmp __b1 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction __b1: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(const byte) a = (byte) 'a' +(void()) main() +(label) main::@1 +(label) main::@return +(const byte) main::b = (byte) 'b' +(byte) main::i loadstore mem[1] 4.6000000000000005 +(byte*) screen +(byte*) screen#1 screen zp[2]:2 16.5 +(byte*) screen#2 screen zp[2]:2 16.5 +(byte*) screen#3 screen zp[2]:2 7.333333333333333 +(byte*) screen#6 screen zp[2]:2 16.5 + +zp[2]:2 [ screen#6 screen#3 screen#1 screen#2 ] +mem[1] [ main::i ] + + +FINAL ASSEMBLER +Score: 952 + + // File Comments +// Test memory model +// Constant memory variables + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .const a = 'a' + .label screen = 2 + // @begin + // [1] phi from @begin to @1 [phi:@begin->@1] + // @1 + // [2] call main + // [3] phi from @1 to @end [phi:@1->@end] + // @end + // main +main: { + .const b = 'b' + // for( char i: 0..5 ) + // [4] (byte) main::i ← (byte) 0 -- vbum1=vbuc1 + lda #0 + sta i + // [5] phi from main to main::@1 [phi:main->main::@1] + // [5] phi (byte*) screen#6 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1 + lda #<$400 + sta.z screen + lda #>$400 + sta.z screen+1 + // [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + // [5] phi (byte*) screen#6 = (byte*) screen#3 [phi:main::@1->main::@1#0] -- register_copy + // main::@1 + __b1: + // *(screen++) = a + // [6] *((byte*) screen#6) ← (const byte) a -- _deref_pbuz1=vbuc1 + lda #a + ldy #0 + sta (screen),y + // *(screen++) = a; + // [7] (byte*) screen#1 ← ++ (byte*) screen#6 -- pbuz1=_inc_pbuz1 + inc.z screen + bne !+ + inc.z screen+1 + !: + // *(screen++) = b + // [8] *((byte*) screen#1) ← (const byte) main::b -- _deref_pbuz1=vbuc1 + lda #b + ldy #0 + sta (screen),y + // *(screen++) = b; + // [9] (byte*) screen#2 ← ++ (byte*) screen#1 -- pbuz1=_inc_pbuz1 + inc.z screen + bne !+ + inc.z screen+1 + !: + // *(screen++) = i + // [10] *((byte*) screen#2) ← (byte) main::i -- _deref_pbuz1=vbum2 + lda i + ldy #0 + sta (screen),y + // *(screen++) = i; + // [11] (byte*) screen#3 ← ++ (byte*) screen#2 -- pbuz1=_inc_pbuz1 + inc.z screen + bne !+ + inc.z screen+1 + !: + // for( char i: 0..5 ) + // [12] (byte) main::i ← ++ (byte) main::i -- vbum1=_inc_vbum1 + inc i + // [13] if((byte) main::i!=(byte) 6) goto main::@1 -- vbum1_neq_vbuc1_then_la1 + lda #6 + cmp i + bne __b1 + // main::@return + // } + // [14] return + rts + i: .byte 0 +} + // File Data + diff --git a/src/test/ref/varmodel-ma_mem-4.sym b/src/test/ref/varmodel-ma_mem-4.sym new file mode 100644 index 000000000..62168d350 --- /dev/null +++ b/src/test/ref/varmodel-ma_mem-4.sym @@ -0,0 +1,17 @@ +(label) @1 +(label) @begin +(label) @end +(const byte) a = (byte) 'a' +(void()) main() +(label) main::@1 +(label) main::@return +(const byte) main::b = (byte) 'b' +(byte) main::i loadstore mem[1] 4.6000000000000005 +(byte*) screen +(byte*) screen#1 screen zp[2]:2 16.5 +(byte*) screen#2 screen zp[2]:2 16.5 +(byte*) screen#3 screen zp[2]:2 7.333333333333333 +(byte*) screen#6 screen zp[2]:2 16.5 + +zp[2]:2 [ screen#6 screen#3 screen#1 screen#2 ] +mem[1] [ main::i ]