diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java b/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java index 756e658c1..88540e693 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java @@ -61,6 +61,9 @@ public class Procedure extends Scope { } } + public void setParameterNames(List parameterNames) { + this.parameterNames = parameterNames; + } public List getComments() { return comments; diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1EarlyConstantIdentification.java b/src/main/java/dk/camelot64/kickc/passes/Pass1EarlyConstantIdentification.java index 8c8339dd9..73521d08c 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1EarlyConstantIdentification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1EarlyConstantIdentification.java @@ -54,7 +54,7 @@ public class Pass1EarlyConstantIdentification extends Pass1Base { } /** - * Examines whether a variale is a procedure parameter + * Examines whether a variable is a procedure parameter * @param variableRef The variable * @return true if the variable is a procedure parameter */ diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java b/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java index c2c9c139b..e9d05299b 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java @@ -2,24 +2,22 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.Comment; import dk.camelot64.kickc.model.ControlFlowBlock; +import dk.camelot64.kickc.model.InternalError; import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.iterator.ProgramValueIterator; import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementAssignment; -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.symbols.VariableIntermediate; +import dk.camelot64.kickc.model.statements.StatementCall; +import dk.camelot64.kickc.model.symbols.*; import dk.camelot64.kickc.model.types.SymbolTypeStruct; +import dk.camelot64.kickc.model.values.RValue; import dk.camelot64.kickc.model.values.StructMemberRef; import dk.camelot64.kickc.model.values.StructZero; import dk.camelot64.kickc.model.values.VariableRef; -import java.util.LinkedHashMap; -import java.util.ListIterator; -import java.util.Map; +import java.util.*; -/** Convert all struct values that are not used as pointers (address-of used or declared volatile) */ +/** Convert all struct values that are not used as pointers (address-of used or declared volatile) into variables representing each member */ public class Pass1UnwindStructValues extends Pass1Base { public Pass1UnwindStructValues(Program program) { @@ -31,7 +29,7 @@ public class Pass1UnwindStructValues extends Pass1Base { boolean modified = false; // Maps struct variable to map from member name to the variable - Map> structMemberVariableMap = new LinkedHashMap<>(); + StructUnwinding structUnwinding = new StructUnwinding(); // Iterate through all scopes generating member-variables for each struct for(Variable variable : getScope().getAllVariables(true)) { @@ -40,7 +38,7 @@ public class Pass1UnwindStructValues extends Pass1Base { // A non-volatile struct variable Scope scope = variable.getScope(); StructDefinition structDefinition = ((SymbolTypeStruct) variable.getType()).getStructDefinition(getProgram().getScope()); - LinkedHashMap memberVariables = new LinkedHashMap<>(); + StructUnwinding.VariableUnwinding variableUnwinding = structUnwinding.createVariableUnwinding(variable.getRef()); for(Variable member : structDefinition.getAllVariables(false)) { Variable memberVariable; if(variable.getRef().isIntermediate()) { @@ -48,14 +46,34 @@ public class Pass1UnwindStructValues extends Pass1Base { } else { memberVariable = scope.addVariable(variable.getLocalName() + "_" + member.getLocalName(), member.getType()); } - memberVariables.put(member.getLocalName(), memberVariable.getRef()); + variableUnwinding.setMemberUnwinding(member.getLocalName(), memberVariable.getRef()); getLog().append("Created struct value member variable " + memberVariable.toString(getProgram())); } - structMemberVariableMap.put(variable.getRef(), memberVariables); getLog().append("Converted struct value to member variables " + variable.toString(getProgram())); } } } + for(Procedure procedure : getScope().getAllProcedures(true)) { + + ArrayList unwoundParameterNames = new ArrayList<>(); + boolean procedureUnwound = false; + for(Variable parameter : procedure.getParameters()) { + if(parameter.getType() instanceof SymbolTypeStruct) { + StructUnwinding.VariableUnwinding parameterUnwinding = structUnwinding.getVariableUnwinding(parameter.getRef()); + for(String memberName : parameterUnwinding.getMemberNames()) { + unwoundParameterNames.add(parameterUnwinding.getMemberUnwinding(memberName).getLocalName()); + procedureUnwound = true; + } + } else { + unwoundParameterNames.add(parameter.getLocalName()); + } + } + if(procedureUnwound) { + procedure.setParameterNames(unwoundParameterNames); + getLog().append("Converted procedure struct value parameter to member variables " + procedure.toString(getProgram())); + } + } + // Unwind all references to full structs for(ControlFlowBlock block : getGraph().getAllBlocks()) { @@ -70,11 +88,11 @@ public class Pass1UnwindStructValues extends Pass1Base { // Assigning a struct! if(assignment.getOperator() == null && assignment.getrValue2() instanceof StructZero) { // Initializing a struct - unwind to assigning zero to each member! - Map memberVariables = structMemberVariableMap.get(assignedVar.getRef()); - if(memberVariables != null) { + StructUnwinding.VariableUnwinding variableUnwinding = structUnwinding.getVariableUnwinding(assignedVar.getRef()); + if(variableUnwinding != null) { stmtIt.previous(); - for(String memberName : memberVariables.keySet()) { - VariableRef memberVarRef = memberVariables.get(memberName); + for(String memberName : variableUnwinding.getMemberNames()) { + VariableRef memberVarRef = variableUnwinding.getMemberUnwinding(memberName); Variable memberVar = getScope().getVariable(memberVarRef); Statement initStmt = Pass0GenerateStatementSequence.createDefaultInitializationStatement(memberVarRef, memberVar.getType(), statement.getSource(), Comment.NO_COMMENTS); stmtIt.add(initStmt); @@ -87,52 +105,147 @@ public class Pass1UnwindStructValues extends Pass1Base { Variable sourceVar = getScope().getVariable((VariableRef) assignment.getrValue2()); if(sourceVar.getType().equals(assignedVar.getType())) { // Copying a struct - unwind to assigning each member! - Map assignedMemberVariables = structMemberVariableMap.get(assignedVar.getRef()); - Map sourceMemberVariables = structMemberVariableMap.get(sourceVar.getRef()); - if(assignedMemberVariables != null && sourceMemberVariables!=null) { + StructUnwinding.VariableUnwinding assignedMemberVariables = structUnwinding.getVariableUnwinding(assignedVar.getRef()); + StructUnwinding.VariableUnwinding sourceMemberVariables = structUnwinding.getVariableUnwinding(sourceVar.getRef()); + if(assignedMemberVariables != null && sourceMemberVariables != null) { stmtIt.previous(); - for(String memberName : assignedMemberVariables.keySet()) { - VariableRef assignedMemberVarRef = assignedMemberVariables.get(memberName); - VariableRef sourceMemberVarRef = sourceMemberVariables.get(memberName); + for(String memberName : assignedMemberVariables.getMemberNames()) { + VariableRef assignedMemberVarRef = assignedMemberVariables.getMemberUnwinding(memberName); + VariableRef sourceMemberVarRef = sourceMemberVariables.getMemberUnwinding(memberName); Statement copyStmt = new StatementAssignment(assignedMemberVarRef, sourceMemberVarRef, statement.getSource(), Comment.NO_COMMENTS); stmtIt.add(copyStmt); getLog().append("Adding struct value member variable copy " + copyStmt.toString(getProgram(), false)); } stmtIt.next(); stmtIt.remove(); + } + } else { + throw new RuntimeException("Struct assignment not implemented yet " + statement.toString(getProgram(), false)); } - } else { - throw new RuntimeException("Struct assignment not implemented yet " + statement.toString(getProgram(), false)); } } } + } else if(statement instanceof StatementCall) { + StatementCall statementCall = (StatementCall) statement; + Procedure procedure = getScope().getProcedure(statementCall.getProcedure()); + ArrayList unwoundParameters = new ArrayList<>(); + boolean anyUnwound = false; + for(RValue parameter : statementCall.getParameters()) { + boolean unwound = false; + if(parameter instanceof VariableRef) { + Variable variable = getScope().getVariable((VariableRef) parameter); + if(variable.getType() instanceof SymbolTypeStruct) { + // Passing a struct variable - convert it to member variables + StructUnwinding.VariableUnwinding variableUnwinding = structUnwinding.getVariableUnwinding((VariableRef) parameter); + if(variableUnwinding!=null) { + for(String memberName : variableUnwinding.getMemberNames()) { + unwoundParameters.add(variableUnwinding.getMemberUnwinding(memberName)); + } + unwound = true; + anyUnwound = true; + } + } + } + if(!unwound) { + unwoundParameters.add(parameter); + } + } + + if(anyUnwound) { + statementCall.setParameters(unwoundParameters); + getLog().append("Converted procedure struct value parameter to member variables in call " + statementCall.toString(getProgram(), false)); + } } } } - } - // Change all usages of members in statements + // Change all usages of members inside statements ProgramValueIterator.execute( - - getProgram(), (programValue,currentStmt,stmtIt,currentBlock)-> - - { - if(programValue.get() instanceof StructMemberRef) { - StructMemberRef structMemberRef = (StructMemberRef) programValue.get(); - if(structMemberRef.getStruct() instanceof VariableRef) { - Variable structVariable = getScope().getVariable((VariableRef) structMemberRef.getStruct()); - Map memberVariables = structMemberVariableMap.get(structVariable.getRef()); - if(memberVariables != null) { - VariableRef structMemberVariable = memberVariables.get(structMemberRef.getMemberName()); - getLog().append("Replacing struct member reference " + structMemberRef.toString(getProgram()) + " with member variable reference " + structMemberVariable.toString(getProgram())); - programValue.set(structMemberVariable); - } - } - } - }); + getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> + { + if(programValue.get() instanceof StructMemberRef) { + StructMemberRef structMemberRef = (StructMemberRef) programValue.get(); + if(structMemberRef.getStruct() instanceof VariableRef) { + Variable structVariable = getScope().getVariable((VariableRef) structMemberRef.getStruct()); + StructUnwinding.VariableUnwinding memberVariables = structUnwinding.getVariableUnwinding(structVariable.getRef()); + if(memberVariables != null) { + VariableRef structMemberVariable = memberVariables.getMemberUnwinding(structMemberRef.getMemberName()); + getLog().append("Replacing struct member reference " + structMemberRef.toString(getProgram()) + " with member variable reference " + structMemberVariable.toString(getProgram())); + programValue.set(structMemberVariable); + } + } + } + }); return modified; -} + } + + /** + * Keeps track of all structs that have been unwound into member variables. + */ + public static class StructUnwinding { + + /** Maps struct variables to unwinding of each member. */ + Map structVariables = new LinkedHashMap<>(); + + /** + * Get information about how a struct variable was unwound into member variables + * + * @param ref The variable to look for + * @return Information about the unwinding. Null if not unwound + */ + public VariableUnwinding getVariableUnwinding(VariableRef ref) { + return structVariables.get(ref); + } + + /** + * Add information about how a struct variable was unwound into member variables + * + * @param ref The variable to add information for + * @return The new information about the unwinding. + */ + public VariableUnwinding createVariableUnwinding(VariableRef ref) { + VariableUnwinding existing = structVariables.put(ref, new VariableUnwinding()); + if(existing != null) { + throw new InternalError("ERROR! Struct unwinding was already created once! " + ref.toString()); + } + return structVariables.get(ref); + } + + + /** Information about how a single struct variable was unwound. */ + public static class VariableUnwinding { + + /** Maps member names to the unwound variables. */ + Map memberUnwinding = new LinkedHashMap<>(); + + /** Set how a member variable was unwound to a specific (new) variable. */ + public void setMemberUnwinding(String memberName, VariableRef memberVariableUnwound) { + this.memberUnwinding.put(memberName, memberVariableUnwound); + } + + /** + * Get the names of the members of the struct + * + * @return the names + */ + public List getMemberNames() { + return new ArrayList<>(memberUnwinding.keySet()); + } + + /** + * Get the (new) variable that a specific member was unwound to + * + * @param memberName The member name + * @return The new variable + */ + public VariableRef getMemberUnwinding(String memberName) { + return this.memberUnwinding.get(memberName); + } + } + + } + } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 3732ca005..0eb72ae40 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -35,6 +35,22 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testStructPtr2() throws IOException, URISyntaxException { + compileAndCompare("struct-ptr-2", log()); + } + + @Test + public void testStructPtr1() throws IOException, URISyntaxException { + compileAndCompare("struct-ptr-1", log()); + } + + @Test + public void testStructPtr0() throws IOException, URISyntaxException { + compileAndCompare("struct-ptr-0", log()); + } + + @Test public void testStruct5() throws IOException, URISyntaxException { @@ -48,7 +64,7 @@ public class TestPrograms { @Test public void testStruct3() throws IOException, URISyntaxException { - compileAndCompare("struct-3", log()); + compileAndCompare("struct-3", log().verboseCreateSsa()); } @Test diff --git a/src/test/kc/struct-3.kc b/src/test/kc/struct-3.kc index d6d25f7df..7402d74c8 100644 --- a/src/test/kc/struct-3.kc +++ b/src/test/kc/struct-3.kc @@ -1,20 +1,23 @@ -// Minimal struct - array of struct +// Minimal struct - passing struct value parameter struct Point { byte x; byte y; }; -struct Point[4] points; - void main() { - for( byte i: 0..4) { - points[i].x = i; - points[i].y = i+1; - } - const byte* SCREEN = 0x0400; - for( byte i: 0..4) { - SCREEN[i] = points[i].x; - (SCREEN+40)[i] = points[i].y; - } + struct Point p1; + p1.x = 1; + p1.y = 4; + print(p1); + p1.x = 2; + print(p1); +} + +const byte* SCREEN = 0x0400; +byte idx = 0; + +void print(struct Point p) { + SCREEN[idx++] = p.x; + SCREEN[idx++] = p.y; } \ No newline at end of file diff --git a/src/test/kc/struct-ptr-0.kc b/src/test/kc/struct-ptr-0.kc new file mode 100644 index 000000000..d6d25f7df --- /dev/null +++ b/src/test/kc/struct-ptr-0.kc @@ -0,0 +1,20 @@ +// Minimal struct - array of struct + +struct Point { + byte x; + byte y; +}; + +struct Point[4] points; + +void main() { + for( byte i: 0..4) { + points[i].x = i; + points[i].y = i+1; + } + const byte* SCREEN = 0x0400; + for( byte i: 0..4) { + SCREEN[i] = points[i].x; + (SCREEN+40)[i] = points[i].y; + } +} \ No newline at end of file diff --git a/src/test/kc/struct-ptr-1.kc b/src/test/kc/struct-ptr-1.kc new file mode 100644 index 000000000..504bb7265 --- /dev/null +++ b/src/test/kc/struct-ptr-1.kc @@ -0,0 +1,24 @@ +// Minimal struct - array of struct - near pointer math indexing + +struct Point { + byte x; + byte y; +}; + +struct Point[4] points; + +const byte SIZEOF_POINT = 2; +const byte OFFS_X = 0; +const byte OFFS_Y = 1; + +void main() { + for( byte i: 0..3) { + *((byte*)points+OFFS_X+i*SIZEOF_POINT) = i; // points[i].x = i; + *((byte*)points+OFFS_Y+i*SIZEOF_POINT) = i+4; // points[i].y = i+4; + } + const byte* SCREEN = 0x0400; + for( byte i: 0..3) { + SCREEN[i] = *((byte*)points+OFFS_X+i*SIZEOF_POINT); // SCREEN[i] = points[i].x; + (SCREEN+40)[i] = *((byte*)points+OFFS_Y+i*SIZEOF_POINT); // (SCREEN+40)[i] = points[i].y; + } +} \ No newline at end of file diff --git a/src/test/kc/struct-ptr-2.kc b/src/test/kc/struct-ptr-2.kc new file mode 100644 index 000000000..1d2cf6cd5 --- /dev/null +++ b/src/test/kc/struct-ptr-2.kc @@ -0,0 +1,26 @@ +// Minimal struct - array of struct - far pointer math indexing + +struct Point { + byte x; + byte y; +}; + +struct Point[4] points; + +const byte SIZEOF_POINT = 2; +const byte OFFS_X = 0; +const byte OFFS_Y = 1; + +void main() { + for( byte i: 0..3) { + struct Point* point_i = points+i; + *((byte*)point_i+OFFS_X) = i; // points[i].x = i; + *((byte*)point_i+OFFS_Y) = i+4; // points[i].y = i+4; + } + const byte* SCREEN = 0x0400; + for( byte i: 0..3) { + struct Point* point_i = points+i; + SCREEN[i] = *((byte*)point_i+OFFS_X); // SCREEN[i] = points[i].x; + (SCREEN+40)[i] = *((byte*)point_i+OFFS_Y); // (SCREEN+40)[i] = points[i].y; + } +} \ No newline at end of file diff --git a/src/test/ref/struct-3.asm b/src/test/ref/struct-3.asm index 998d77eb6..8dca00250 100644 --- a/src/test/ref/struct-3.asm +++ b/src/test/ref/struct-3.asm @@ -1,39 +1,23 @@ -// Minimal struct - array of struct +// Minimal struct - passing struct value parameter .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" + .label SCREEN = $400 main: { - .label SCREEN = $400 - .label _5 = 2 + .label p1_y = 4 ldx #0 - b1: - txa - asl - sta _5 - tay - txa - sta points,y - txa - tay - iny - tya - ldy _5 - sta points+1,y - inx - cpx #5 - bne b1 - ldy #0 - b2: - tya - asl - tax - lda points,x - sta SCREEN,y - lda points+1,x - sta SCREEN+$28,y - iny - cpy #5 - bne b2 + lda #1 + jsr print + lda #2 + jsr print + rts +} +// print(byte register(A) p_x) +print: { + sta SCREEN,x + inx + lda #main.p1_y + sta SCREEN,x + inx rts } - points: .fill 2*4, 0 diff --git a/src/test/ref/struct-3.cfg b/src/test/ref/struct-3.cfg index 77cf1ccaf..7ec77e170 100644 --- a/src/test/ref/struct-3.cfg +++ b/src/test/ref/struct-3.cfg @@ -9,24 +9,23 @@ [3] phi() main: scope:[main] from @1 [4] phi() + [5] call print 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 ) - [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 - [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 - [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 - [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 - [10] (byte) main::i#1 ← ++ (byte) main::i#2 - [11] if((byte) main::i#1!=(byte) 5) goto main::@1 - to:main::@2 -main::@2: scope:[main] from main::@1 main::@2 - [12] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) - [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 - [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x - [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y - [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 - [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 +main::@1: scope:[main] from main + [6] phi() + [7] call print to:main::@return -main::@return: scope:[main] from main::@2 - [18] return +main::@return: scope:[main] from main::@1 + [8] return + to:@return +print: scope:[print] from main main::@1 + [9] (byte) idx#11 ← phi( main/(byte) 0 main::@1/(byte) idx#12 ) + [9] (byte) print::p_x#2 ← phi( main/(byte) 1 main::@1/(byte) 2 ) + [10] *((const byte*) SCREEN#0 + (byte) idx#11) ← (byte) print::p_x#2 + [11] (byte) idx#4 ← ++ (byte) idx#11 + [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (const byte) main::p1_y#1 + [13] (byte) idx#12 ← ++ (byte) idx#4 + to:print::@return +print::@return: scope:[print] from print + [14] return to:@return diff --git a/src/test/ref/struct-3.log b/src/test/ref/struct-3.log index 5d7f09b74..52228b6e0 100644 --- a/src/test/ref/struct-3.log +++ b/src/test/ref/struct-3.log @@ -1,169 +1,285 @@ -Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i) -Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i) -Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i1) -Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i1) -Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 -Culled Empty Block (label) main::@4 - -CONTROL FLOW GRAPH SSA -@begin: scope:[] from - (struct Point[4]) points#0 ← { fill( 4, 0) } - to:@1 -main: scope:[main] from @1 - (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~) main::$4 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT - *((struct Point[4]) points#0 + (byte~) main::$4).x ← (byte) main::i#2 - (number~) main::$0 ← (byte) main::i#2 + (number) 1 - (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT - *((struct Point[4]) points#0 + (byte~) main::$5).y ← (number~) main::$0 - (byte) main::i#1 ← (byte) main::i#2 + rangenext(0,4) - (bool~) main::$1 ← (byte) main::i#1 != rangelast(0,4) - if((bool~) main::$1) goto main::@1 - to:main::@2 -main::@2: scope:[main] from main::@1 - (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 - (byte) main::i1#0 ← (byte) 0 - to:main::@3 -main::@3: scope:[main] from main::@2 main::@3 - (byte) main::i1#2 ← phi( main::@2/(byte) main::i1#0 main::@3/(byte) main::i1#1 ) - (byte~) main::$6 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT - *((byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((struct Point[4]) points#0 + (byte~) main::$6).x - (byte*~) main::$2 ← (byte*) main::SCREEN#0 + (number) $28 - (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT - *((byte*~) main::$2 + (byte) main::i1#2) ← *((struct Point[4]) points#0 + (byte~) main::$7).y - (byte) main::i1#1 ← (byte) main::i1#2 + rangenext(0,4) - (bool~) main::$3 ← (byte) main::i1#1 != rangelast(0,4) - if((bool~) main::$3) goto main::@3 - to:main::@return -main::@return: scope:[main] from main::@3 - return - to:@return -@1: scope:[] from @begin - call main - to:@2 -@2: scope:[] from @1 - to:@end -@end: scope:[] from @2 - -SYMBOL TABLE SSA +Created struct value member variable (byte) main::p1_x +Created struct value member variable (byte) main::p1_y +Converted struct value to member variables (struct Point) main::p1 +Created struct value member variable (byte) print::p_x +Created struct value member variable (byte) print::p_y +Converted struct value to member variables (struct Point) print::p +Converted procedure struct value parameter to member variables (void()) print((byte) print::p_x , (byte) print::p_y) +Adding struct value member variable default initializer (byte) main::p1_x ← (byte) 0 +Adding struct value member variable default initializer (byte) main::p1_y ← (byte) 0 +Converted procedure struct value parameter to member variables in call (void~) main::$0 ← call print (byte) main::p1_x (byte) main::p1_y +Converted procedure struct value parameter to member variables in call (void~) main::$1 ← call print (byte) main::p1_x (byte) main::p1_y +Replacing struct member reference (struct Point) main::p1.x with member variable reference (byte) main::p1_x +Replacing struct member reference (struct Point) main::p1.y with member variable reference (byte) main::p1_y +Replacing struct member reference (struct Point) main::p1.x with member variable reference (byte) main::p1_x +Replacing struct member reference (struct Point) print::p.x with member variable reference (byte) print::p_x +Replacing struct member reference (struct Point) print::p.y with member variable reference (byte) print::p_y +SYMBOLS (label) @1 (label) @2 (label) @begin (label) @end (byte) Point::x (byte) Point::y -(const byte) SIZEOF_STRUCT_POINT = (byte) 2 +(byte*) SCREEN +(byte) idx +(void()) main() +(void~) main::$0 +(void~) main::$1 +(label) main::@return +(struct Point) main::p1 +(byte) main::p1_x +(byte) main::p1_y +(void()) print((byte) print::p_x , (byte) print::p_y) +(label) print::@return +(struct Point) print::p +(byte) print::p_x +(byte) print::p_y + +Adding pointer type conversion cast (byte*) SCREEN in (byte*) SCREEN ← (number) $400 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from + [0] (byte) main::p1_x ← (byte) 0 + [1] (byte) main::p1_y ← (byte) 0 + [2] (byte) main::p1_x ← (number) 1 + [3] (byte) main::p1_y ← (number) 4 + [4] (void~) main::$0 ← call print (byte) main::p1_x (byte) main::p1_y + [5] (byte) main::p1_x ← (number) 2 + [6] (void~) main::$1 ← call print (byte) main::p1_x (byte) main::p1_y + to:main::@return +main::@return: scope:[main] from main + [7] return + to:@return +@1: scope:[] from @begin + [8] (byte*) SCREEN ← ((byte*)) (number) $400 + [9] (byte) idx ← (number) 0 + to:@2 +print: scope:[print] from + [10] *((byte*) SCREEN + (byte) idx) ← (byte) print::p_x + [11] (byte) idx ← ++ (byte) idx + [12] *((byte*) SCREEN + (byte) idx) ← (byte) print::p_y + [13] (byte) idx ← ++ (byte) idx + to:print::@return +print::@return: scope:[print] from print + [14] return + to:@return +@2: scope:[] from @1 + [15] call main + to:@end +@end: scope:[] from @2 + +Eliminating unused variable - keeping the call (void~) main::$0 +Eliminating unused variable - keeping the call (void~) main::$1 +PROCEDURE MODIFY VARIABLE ANALYSIS +main modifies idx +print modifies idx + +Completing Phi functions... +Completing Phi functions... + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @2 + (byte) idx#14 ← phi( @2/(byte) idx#15 ) + (byte) main::p1_x#0 ← (byte) 0 + (byte) main::p1_y#0 ← (byte) 0 + (byte) main::p1_x#1 ← (number) 1 + (byte) main::p1_y#1 ← (number) 4 + (byte) print::p_x#0 ← (byte) main::p1_x#1 + (byte) print::p_y#0 ← (byte) main::p1_y#1 + call print + to:main::@1 +main::@1: scope:[main] from main + (byte) main::p1_y#2 ← phi( main/(byte) main::p1_y#1 ) + (byte) idx#8 ← phi( main/(byte) idx#6 ) + (byte) idx#0 ← (byte) idx#8 + (byte) main::p1_x#2 ← (number) 2 + (byte) print::p_x#1 ← (byte) main::p1_x#2 + (byte) print::p_y#1 ← (byte) main::p1_y#2 + call print + to:main::@2 +main::@2: scope:[main] from main::@1 + (byte) idx#9 ← phi( main::@1/(byte) idx#6 ) + (byte) idx#1 ← (byte) idx#9 + to:main::@return +main::@return: scope:[main] from main::@2 + (byte) idx#10 ← phi( main::@2/(byte) idx#1 ) + (byte) idx#2 ← (byte) idx#10 + return + to:@return +@1: scope:[] from @begin + (byte*) SCREEN#0 ← ((byte*)) (number) $400 + (byte) idx#3 ← (number) 0 + to:@2 +print: scope:[print] from main main::@1 + (byte) print::p_y#2 ← phi( main/(byte) print::p_y#0 main::@1/(byte) print::p_y#1 ) + (byte) idx#11 ← phi( main/(byte) idx#14 main::@1/(byte) idx#0 ) + (byte) print::p_x#2 ← phi( main/(byte) print::p_x#0 main::@1/(byte) print::p_x#1 ) + *((byte*) SCREEN#0 + (byte) idx#11) ← (byte) print::p_x#2 + (byte) idx#4 ← ++ (byte) idx#11 + *((byte*) SCREEN#0 + (byte) idx#4) ← (byte) print::p_y#2 + (byte) idx#5 ← ++ (byte) idx#4 + to:print::@return +print::@return: scope:[print] from print + (byte) idx#12 ← phi( print/(byte) idx#5 ) + (byte) idx#6 ← (byte) idx#12 + return + to:@return +@2: scope:[] from @1 + (byte) idx#15 ← phi( @1/(byte) idx#3 ) + call main + to:@3 +@3: scope:[] from @2 + (byte) idx#13 ← phi( @2/(byte) idx#2 ) + (byte) idx#7 ← (byte) idx#13 + to:@end +@end: scope:[] from @3 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @3 +(label) @begin +(label) @end +(byte) Point::x +(byte) Point::y +(byte*) SCREEN +(byte*) SCREEN#0 +(byte) idx +(byte) idx#0 +(byte) idx#1 +(byte) idx#10 +(byte) idx#11 +(byte) idx#12 +(byte) idx#13 +(byte) idx#14 +(byte) idx#15 +(byte) idx#2 +(byte) idx#3 +(byte) idx#4 +(byte) idx#5 +(byte) idx#6 +(byte) idx#7 +(byte) idx#8 +(byte) idx#9 (void()) main() -(number~) main::$0 -(bool~) main::$1 -(byte*~) main::$2 -(bool~) main::$3 -(byte~) main::$4 -(byte~) main::$5 -(byte~) main::$6 -(byte~) main::$7 (label) main::@1 (label) main::@2 -(label) main::@3 (label) main::@return -(byte*) main::SCREEN -(byte*) main::SCREEN#0 -(byte) main::i -(byte) main::i#0 -(byte) main::i#1 -(byte) main::i#2 -(byte) main::i1 -(byte) main::i1#0 -(byte) main::i1#1 -(byte) main::i1#2 -(struct Point[4]) points -(struct Point[4]) points#0 +(struct Point) main::p1 +(byte) main::p1_x +(byte) main::p1_x#0 +(byte) main::p1_x#1 +(byte) main::p1_x#2 +(byte) main::p1_y +(byte) main::p1_y#0 +(byte) main::p1_y#1 +(byte) main::p1_y#2 +(void()) print((byte) print::p_x , (byte) print::p_y) +(label) print::@return +(struct Point) print::p +(byte) print::p_x +(byte) print::p_x#0 +(byte) print::p_x#1 +(byte) print::p_x#2 +(byte) print::p_y +(byte) print::p_y#0 +(byte) print::p_y#1 +(byte) print::p_y#2 -Adding number conversion cast (unumber) 1 in (number~) main::$0 ← (byte) main::i#2 + (number) 1 -Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (byte) main::i#2 + (unumber)(number) 1 -Adding number conversion cast (unumber) $28 in (byte*~) main::$2 ← (byte*) main::SCREEN#0 + (number) $28 +Adding number conversion cast (unumber) 1 in (byte) main::p1_x#1 ← (number) 1 +Adding number conversion cast (unumber) 4 in (byte) main::p1_y#1 ← (number) 4 +Adding number conversion cast (unumber) 2 in (byte) main::p1_x#2 ← (number) 2 +Adding number conversion cast (unumber) 0 in (byte) idx#3 ← (number) 0 Successful SSA optimization PassNAddNumberTypeConversions -Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 +Inlining cast (byte) main::p1_x#1 ← (unumber)(number) 1 +Inlining cast (byte) main::p1_y#1 ← (unumber)(number) 4 +Inlining cast (byte) main::p1_x#2 ← (unumber)(number) 2 +Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 +Inlining cast (byte) idx#3 ← (unumber)(number) 0 Successful SSA optimization Pass2InlineCast Simplifying constant integer cast 1 +Simplifying constant integer cast 4 +Simplifying constant integer cast 2 Simplifying constant pointer cast (byte*) 1024 -Simplifying constant integer cast $28 +Simplifying constant integer cast 0 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) 1 -Finalized unsigned number type (byte) $28 +Finalized unsigned number type (byte) 4 +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 0 Successful SSA optimization PassNFinalizeNumberTypeConversions -Inferred type updated to byte in (unumber~) main::$0 ← (byte) main::i#2 + (byte) 1 -Identified duplicate assignment right side [6] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT -Identified duplicate assignment right side [17] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT -Successful SSA optimization Pass2DuplicateRValueIdentification -Simple Condition (bool~) main::$1 [10] if((byte) main::i#1!=rangelast(0,4)) goto main::@1 -Simple Condition (bool~) main::$3 [21] if((byte) main::i1#1!=rangelast(0,4)) goto main::@3 -Successful SSA optimization Pass2ConditionalJumpSimplification -Constant right-side identified [0] (struct Point[4]) points#0 ← { fill( 4, 0) } -Successful SSA optimization Pass2ConstantRValueConsolidation -Constant (const struct Point[4]) points#0 = { fill( 4, 0) } -Constant (const byte) main::i#0 = 0 -Constant (const byte*) main::SCREEN#0 = (byte*) 1024 -Constant (const byte) main::i1#0 = 0 -Successful SSA optimization Pass2ConstantIdentification -Resolved ranged next value [8] main::i#1 ← ++ main::i#2 to ++ -Resolved ranged comparison value [10] if(main::i#1!=rangelast(0,4)) goto main::@1 to (number) 5 -Resolved ranged next value [19] main::i1#1 ← ++ main::i1#2 to ++ -Resolved ranged comparison value [21] if(main::i1#1!=rangelast(0,4)) goto main::@3 to (number) 5 -Adding number conversion cast (unumber) 5 in if((byte) main::i#1!=(number) 5) goto main::@1 -Adding number conversion cast (unumber) 5 in if((byte) main::i1#1!=(number) 5) goto main::@3 -Successful SSA optimization PassNAddNumberTypeConversions -Simplifying constant integer cast 5 -Simplifying constant integer cast 5 -Successful SSA optimization PassNCastSimplification -Finalized unsigned number type (byte) 5 -Finalized unsigned number type (byte) 5 -Successful SSA optimization PassNFinalizeNumberTypeConversions -Alias (byte~) main::$5 = (byte~) main::$4 -Alias (byte~) main::$7 = (byte~) main::$6 +Alias (byte) main::p1_y#1 = (byte) main::p1_y#2 +Alias (byte) idx#0 = (byte) idx#8 +Alias (byte) idx#1 = (byte) idx#9 (byte) idx#10 (byte) idx#2 +Alias (byte) idx#12 = (byte) idx#5 (byte) idx#6 +Alias (byte) idx#15 = (byte) idx#3 +Alias (byte) idx#13 = (byte) idx#7 Successful SSA optimization Pass2AliasElimination -Constant right-side identified [11] (byte*~) main::$2 ← (const byte*) main::SCREEN#0 + (byte) $28 -Successful SSA optimization Pass2ConstantRValueConsolidation -Constant (const byte*) main::$2 = main::SCREEN#0+$28 +Identical Phi Values (byte) idx#14 (byte) idx#15 +Identical Phi Values (byte) idx#0 (byte) idx#12 +Identical Phi Values (byte) idx#1 (byte) idx#12 +Identical Phi Values (byte) idx#13 (byte) idx#1 +Successful SSA optimization Pass2IdenticalPhiElimination +Constant (const byte) main::p1_x#0 = 0 +Constant (const byte) main::p1_y#0 = 0 +Constant (const byte) main::p1_x#1 = 1 +Constant (const byte) main::p1_y#1 = 4 +Constant (const byte) main::p1_x#2 = 2 +Constant (const byte*) SCREEN#0 = (byte*) 1024 +Constant (const byte) idx#15 = 0 Successful SSA optimization Pass2ConstantIdentification -Rewriting multiplication to use shift [1] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT -Rewriting multiplication to use shift [8] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT -Successful SSA optimization Pass2MultiplyToShiftRewriting -Inlining constant with var siblings (const byte) main::i#0 -Inlining constant with var siblings (const byte) main::i1#0 -Constant inlined main::i#0 = (byte) 0 -Constant inlined main::i1#0 = (byte) 0 -Constant inlined main::$2 = (const byte*) main::SCREEN#0+(byte) $28 -Successful SSA optimization Pass2ConstantInlining -Eliminating unused constant (const byte) SIZEOF_STRUCT_POINT +Constant (const byte) print::p_x#0 = main::p1_x#1 +Constant (const byte) print::p_y#0 = main::p1_y#1 +Constant (const byte) print::p_x#1 = main::p1_x#2 +Constant (const byte) print::p_y#1 = main::p1_y#1 +Successful SSA optimization Pass2ConstantIdentification +Eliminating unused constant (const byte) main::p1_x#0 +Eliminating unused constant (const byte) main::p1_y#0 Successful SSA optimization PassNEliminateUnusedVars -Added new block during phi lifting main::@5(between main::@1 and main::@1) -Added new block during phi lifting main::@6(between main::@3 and main::@3) +Inlining constant with different constant siblings (const byte) main::p1_x#1 +Inlining constant with different constant siblings (const byte) main::p1_x#2 +Inlining constant with var siblings (const byte) print::p_x#0 +Inlining constant with var siblings (const byte) print::p_y#0 +Inlining constant with var siblings (const byte) print::p_x#1 +Inlining constant with var siblings (const byte) print::p_y#1 +Inlining constant with var siblings (const byte) idx#15 +Constant inlined print::p_x#0 = (byte) 1 +Constant inlined print::p_y#1 = (const byte) main::p1_y#1 +Constant inlined print::p_y#0 = (const byte) main::p1_y#1 +Constant inlined print::p_x#1 = (byte) 2 +Constant inlined main::p1_x#2 = (byte) 2 +Constant inlined main::p1_x#1 = (byte) 1 +Constant inlined idx#15 = (byte) 0 +Successful SSA optimization Pass2ConstantInlining +Identical Phi Values (byte) print::p_y#2 (const byte) main::p1_y#1 +Successful SSA optimization Pass2IdenticalPhiElimination 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 @3 Adding NOP phi() at start of @end Adding NOP phi() at start of main Adding NOP phi() at start of main::@2 CALL GRAPH -Calls in [] to main:2 +Calls in [] to main:3 +Calls in [main] to print:7 print:9 Created 2 initial phi equivalence classes -Coalesced [21] main::i1#3 ← main::i1#1 -Coalesced [22] main::i#3 ← main::i#1 +Coalesced [8] idx#16 ← idx#12 Coalesced down to 2 phi equivalence classes -Culled Empty Block (label) @2 +Culled Empty Block (label) @1 +Culled Empty Block (label) @3 Culled Empty Block (label) main::@2 -Culled Empty Block (label) main::@6 -Culled Empty Block (label) main::@5 -Renumbering block main::@3 to main::@2 +Renumbering block @2 to @1 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 +Adding NOP phi() at start of main::@1 FINAL CONTROL FLOW GRAPH @begin: scope:[] from @@ -177,71 +293,70 @@ FINAL CONTROL FLOW GRAPH [3] phi() main: scope:[main] from @1 [4] phi() + [5] call print 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 ) - [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 - [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 - [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 - [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 - [10] (byte) main::i#1 ← ++ (byte) main::i#2 - [11] if((byte) main::i#1!=(byte) 5) goto main::@1 - to:main::@2 -main::@2: scope:[main] from main::@1 main::@2 - [12] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) - [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 - [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x - [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y - [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 - [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 +main::@1: scope:[main] from main + [6] phi() + [7] call print to:main::@return -main::@return: scope:[main] from main::@2 - [18] return +main::@return: scope:[main] from main::@1 + [8] return + to:@return +print: scope:[print] from main main::@1 + [9] (byte) idx#11 ← phi( main/(byte) 0 main::@1/(byte) idx#12 ) + [9] (byte) print::p_x#2 ← phi( main/(byte) 1 main::@1/(byte) 2 ) + [10] *((const byte*) SCREEN#0 + (byte) idx#11) ← (byte) print::p_x#2 + [11] (byte) idx#4 ← ++ (byte) idx#11 + [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (const byte) main::p1_y#1 + [13] (byte) idx#12 ← ++ (byte) idx#4 + to:print::@return +print::@return: scope:[print] from print + [14] return to:@return VARIABLE REGISTER WEIGHTS (byte) Point::x (byte) Point::y +(byte*) SCREEN +(byte) idx +(byte) idx#11 3.0 +(byte) idx#12 1.0 +(byte) idx#4 3.0 (void()) main() -(byte~) main::$0 22.0 -(byte~) main::$5 3.6666666666666665 -(byte~) main::$7 5.5 -(byte*) main::SCREEN -(byte) main::i -(byte) main::i#1 16.5 -(byte) main::i#2 11.0 -(byte) main::i1 -(byte) main::i1#1 16.5 -(byte) main::i1#2 13.75 -(struct Point[4]) points +(struct Point) main::p1 +(byte) main::p1_x +(byte) main::p1_y +(void()) print((byte) print::p_x , (byte) print::p_y) +(struct Point) print::p +(byte) print::p_x +(byte) print::p_x#2 2.0 +(byte) print::p_y Initial phi equivalence classes -[ main::i#2 main::i#1 ] -[ main::i1#2 main::i1#1 ] -Added variable main::$5 to zero page equivalence class [ main::$5 ] -Added variable main::$0 to zero page equivalence class [ main::$0 ] -Added variable main::$7 to zero page equivalence class [ main::$7 ] +[ print::p_x#2 ] +[ idx#11 idx#12 ] +Added variable idx#4 to zero page equivalence class [ idx#4 ] Complete equivalence classes -[ main::i#2 main::i#1 ] -[ main::i1#2 main::i1#1 ] -[ main::$5 ] -[ main::$0 ] -[ main::$7 ] -Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] -Allocated zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] -Allocated zp ZP_BYTE:4 [ main::$5 ] -Allocated zp ZP_BYTE:5 [ main::$0 ] -Allocated zp ZP_BYTE:6 [ main::$7 ] +[ print::p_x#2 ] +[ idx#11 idx#12 ] +[ idx#4 ] +Allocated zp ZP_BYTE:2 [ print::p_x#2 ] +Allocated zp ZP_BYTE:3 [ idx#11 idx#12 ] +Allocated zp ZP_BYTE:4 [ idx#4 ] INITIAL ASM //SEG0 File Comments -// Minimal struct - array of struct +// Minimal struct - passing struct value parameter //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels + .label SCREEN = $400 + .label idx = 4 + .label idx_11 = 3 + .label idx_12 = 3 //SEG3 @begin bbegin: //SEG4 [1] phi from @begin to @1 [phi:@begin->@1] @@ -260,128 +375,91 @@ bend_from_b1: bend: //SEG10 main main: { - .label SCREEN = $400 - .label _0 = 5 - .label _5 = 4 - .label _7 = 6 - .label i = 2 - .label i1 = 3 - //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + .label p1_y = 4 + //SEG11 [5] call print + //SEG12 [9] phi from main to print [phi:main->print] + print_from_main: + //SEG13 [9] phi (byte) idx#11 = (byte) 0 [phi:main->print#0] -- vbuz1=vbuc1 + lda #0 + sta idx_11 + //SEG14 [9] phi (byte) print::p_x#2 = (byte) 1 [phi:main->print#1] -- vbuz1=vbuc1 + lda #1 + sta print.p_x + jsr print + //SEG15 [6] phi from main to main::@1 [phi:main->main::@1] b1_from_main: - //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 - lda #0 - sta i jmp b1 - //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] - b1_from_b1: - //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy - jmp b1 - //SEG15 main::@1 + //SEG16 main::@1 b1: - //SEG16 [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 - lda i - asl - sta _5 - //SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuz2 - lda i - ldy _5 - sta points,y - //SEG18 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuz1=vbuz2_plus_1 - ldy i - iny - sty _0 - //SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuz2 - lda _0 - ldy _5 - sta points+1,y - //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 - inc i - //SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 - lda #5 - cmp i - bne b1_from_b1 - //SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2] - b2_from_b1: - //SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 - lda #0 - sta i1 - jmp b2 - //SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2] - b2_from_b2: - //SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy - jmp b2 - //SEG26 main::@2 - b2: - //SEG27 [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 - lda i1 - asl - sta _7 - //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuz1=pssc2_derefidx_vbuz2_mbr_0 - ldx _7 - lda points,x - ldx i1 - sta SCREEN,x - //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuz1=pssc2_derefidx_vbuz2_mbr_1 - ldx _7 - lda points+1,x - ldx i1 - sta SCREEN+$28,x - //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1 - inc i1 - //SEG31 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 -- vbuz1_neq_vbuc1_then_la1 - lda #5 - cmp i1 - bne b2_from_b2 + //SEG17 [7] call print + //SEG18 [9] phi from main::@1 to print [phi:main::@1->print] + print_from_b1: + //SEG19 [9] phi (byte) idx#11 = (byte) idx#12 [phi:main::@1->print#0] -- register_copy + //SEG20 [9] phi (byte) print::p_x#2 = (byte) 2 [phi:main::@1->print#1] -- vbuz1=vbuc1 + lda #2 + sta print.p_x + jsr print jmp breturn - //SEG32 main::@return + //SEG21 main::@return breturn: - //SEG33 [18] return + //SEG22 [8] return + rts +} +//SEG23 print +// print(byte zeropage(2) p_x) +print: { + .label p_x = 2 + //SEG24 [10] *((const byte*) SCREEN#0 + (byte) idx#11) ← (byte) print::p_x#2 -- pbuc1_derefidx_vbuz1=vbuz2 + lda p_x + ldy idx_11 + sta SCREEN,y + //SEG25 [11] (byte) idx#4 ← ++ (byte) idx#11 -- vbuz1=_inc_vbuz2 + ldy idx_11 + iny + sty idx + //SEG26 [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (const byte) main::p1_y#1 -- pbuc1_derefidx_vbuz1=vbuc2 + lda #main.p1_y + ldy idx + sta SCREEN,y + //SEG27 [13] (byte) idx#12 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz2 + ldy idx + iny + sty idx_12 + jmp breturn + //SEG28 print::@return + breturn: + //SEG29 [14] return rts } - points: .fill 2*4, 0 REGISTER UPLIFT POTENTIAL REGISTERS -Statement [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) 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 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::$5 ] -Statement [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] -Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ main::$7 ] -Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a -Statement [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a -Statement [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a -Statement [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a -Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a -Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y [ main::i1#2 ] ( main:2 [ main::i1#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 , -Potential registers zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , -Potential registers zp ZP_BYTE:4 [ main::$5 ] : zp ZP_BYTE:4 , reg byte x , reg byte y , -Potential registers zp ZP_BYTE:5 [ main::$0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y , -Potential registers zp ZP_BYTE:6 [ main::$7 ] : zp ZP_BYTE:6 , reg byte x , reg byte y , +Statement [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (const byte) main::p1_y#1 [ idx#4 ] ( main:2::print:5 [ idx#4 ] main:2::print:7 [ idx#4 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ idx#4 ] +Statement [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (const byte) main::p1_y#1 [ idx#4 ] ( main:2::print:5 [ idx#4 ] main:2::print:7 [ idx#4 ] ) always clobbers reg byte a +Potential registers zp ZP_BYTE:2 [ print::p_x#2 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:3 [ idx#11 idx#12 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:4 [ idx#4 ] : zp ZP_BYTE:4 , reg byte x , reg byte y , REGISTER UPLIFT SCOPES -Uplift Scope [main] 30.25: zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] 27.5: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:5 [ main::$0 ] 5.5: zp ZP_BYTE:6 [ main::$7 ] 3.67: zp ZP_BYTE:4 [ main::$5 ] +Uplift Scope [] 4: zp ZP_BYTE:3 [ idx#11 idx#12 ] 3: zp ZP_BYTE:4 [ idx#4 ] +Uplift Scope [print] 2: zp ZP_BYTE:2 [ print::p_x#2 ] Uplift Scope [Point] -Uplift Scope [] +Uplift Scope [main] -Uplifting [main] best 918 combination reg byte y [ main::i1#2 main::i1#1 ] reg byte x [ main::i#2 main::i#1 ] reg byte y [ main::$0 ] reg byte x [ main::$7 ] zp ZP_BYTE:4 [ main::$5 ] -Limited combination testing to 100 combinations of 324 possible. -Uplifting [Point] best 918 combination -Uplifting [] best 918 combination -Attempting to uplift remaining variables inzp ZP_BYTE:4 [ main::$5 ] -Uplifting [main] best 918 combination zp ZP_BYTE:4 [ main::$5 ] -Allocated (was zp ZP_BYTE:4) zp ZP_BYTE:2 [ main::$5 ] +Uplifting [] best 76 combination reg byte x [ idx#11 idx#12 ] reg byte x [ idx#4 ] +Uplifting [print] best 67 combination reg byte a [ print::p_x#2 ] +Uplifting [Point] best 67 combination +Uplifting [main] best 67 combination ASSEMBLER BEFORE OPTIMIZATION //SEG0 File Comments -// Minimal struct - array of struct +// Minimal struct - passing struct value parameter //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels + .label SCREEN = $400 //SEG3 @begin bbegin: //SEG4 [1] phi from @begin to @1 [phi:@begin->@1] @@ -400,102 +478,75 @@ bend_from_b1: bend: //SEG10 main main: { - .label SCREEN = $400 - .label _5 = 2 - //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] - b1_from_main: - //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + .label p1_y = 4 + //SEG11 [5] call print + //SEG12 [9] phi from main to print [phi:main->print] + print_from_main: + //SEG13 [9] phi (byte) idx#11 = (byte) 0 [phi:main->print#0] -- vbuxx=vbuc1 ldx #0 + //SEG14 [9] phi (byte) print::p_x#2 = (byte) 1 [phi:main->print#1] -- vbuaa=vbuc1 + lda #1 + jsr print + //SEG15 [6] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: jmp b1 - //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] - b1_from_b1: - //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy - jmp b1 - //SEG15 main::@1 + //SEG16 main::@1 b1: - //SEG16 [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuxx_rol_1 - txa - asl - sta _5 - //SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuxx - ldy _5 - txa - sta points,y - //SEG18 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuyy=vbuxx_plus_1 - txa - tay - iny - //SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuyy - tya - ldy _5 - sta points+1,y - //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx - inx - //SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 - cpx #5 - bne b1_from_b1 - //SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2] - b2_from_b1: - //SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 - ldy #0 - jmp b2 - //SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2] - b2_from_b2: - //SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy - jmp b2 - //SEG26 main::@2 - b2: - //SEG27 [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuxx=vbuyy_rol_1 - tya - asl - tax - //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_0 - lda points,x - sta SCREEN,y - //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_1 - lda points+1,x - sta SCREEN+$28,y - //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy - iny - //SEG31 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 -- vbuyy_neq_vbuc1_then_la1 - cpy #5 - bne b2_from_b2 + //SEG17 [7] call print + //SEG18 [9] phi from main::@1 to print [phi:main::@1->print] + print_from_b1: + //SEG19 [9] phi (byte) idx#11 = (byte) idx#12 [phi:main::@1->print#0] -- register_copy + //SEG20 [9] phi (byte) print::p_x#2 = (byte) 2 [phi:main::@1->print#1] -- vbuaa=vbuc1 + lda #2 + jsr print jmp breturn - //SEG32 main::@return + //SEG21 main::@return breturn: - //SEG33 [18] return + //SEG22 [8] return + rts +} +//SEG23 print +// print(byte register(A) p_x) +print: { + //SEG24 [10] *((const byte*) SCREEN#0 + (byte) idx#11) ← (byte) print::p_x#2 -- pbuc1_derefidx_vbuxx=vbuaa + sta SCREEN,x + //SEG25 [11] (byte) idx#4 ← ++ (byte) idx#11 -- vbuxx=_inc_vbuxx + inx + //SEG26 [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (const byte) main::p1_y#1 -- pbuc1_derefidx_vbuxx=vbuc2 + lda #main.p1_y + sta SCREEN,x + //SEG27 [13] (byte) idx#12 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx + inx + jmp breturn + //SEG28 print::@return + breturn: + //SEG29 [14] return rts } - points: .fill 2*4, 0 ASSEMBLER OPTIMIZATIONS Removing instruction jmp b1 Removing instruction jmp bend Removing instruction jmp b1 -Removing instruction jmp b2 +Removing instruction jmp breturn Removing instruction jmp breturn Succesful ASM optimization Pass5NextJumpElimination -Replacing instruction ldy _5 with TAY -Replacing label b1_from_b1 with b1 -Replacing label b2_from_b2 with b2 Removing instruction b1_from_bbegin: Removing instruction b1: Removing instruction main_from_b1: Removing instruction bend_from_b1: -Removing instruction b1_from_b1: -Removing instruction b2_from_b2: +Removing instruction b1_from_main: +Removing instruction print_from_b1: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction bend: -Removing instruction b1_from_main: -Removing instruction b2_from_b1: +Removing instruction print_from_main: +Removing instruction b1: +Removing instruction breturn: 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 -Removing instruction jmp b2 -Succesful ASM optimization Pass5NextJumpElimination Removing instruction bbegin: Succesful ASM optimization Pass5UnusedLabelElimination @@ -505,41 +556,42 @@ FINAL SYMBOL TABLE (label) @end (byte) Point::x (byte) Point::y +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(byte) idx +(byte) idx#11 reg byte x 3.0 +(byte) idx#12 reg byte x 1.0 +(byte) idx#4 reg byte x 3.0 (void()) main() -(byte~) main::$0 reg byte y 22.0 -(byte~) main::$5 $5 zp ZP_BYTE:2 3.6666666666666665 -(byte~) main::$7 reg byte x 5.5 (label) main::@1 -(label) main::@2 (label) main::@return -(byte*) main::SCREEN -(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 -(byte) main::i -(byte) main::i#1 reg byte x 16.5 -(byte) main::i#2 reg byte x 11.0 -(byte) main::i1 -(byte) main::i1#1 reg byte y 16.5 -(byte) main::i1#2 reg byte y 13.75 -(struct Point[4]) points -(const struct Point[4]) points#0 points = { fill( 4, 0) } +(struct Point) main::p1 +(byte) main::p1_x +(byte) main::p1_y +(const byte) main::p1_y#1 p1_y = (byte) 4 +(void()) print((byte) print::p_x , (byte) print::p_y) +(label) print::@return +(struct Point) print::p +(byte) print::p_x +(byte) print::p_x#2 reg byte a 2.0 +(byte) print::p_y -reg byte x [ main::i#2 main::i#1 ] -reg byte y [ main::i1#2 main::i1#1 ] -zp ZP_BYTE:2 [ main::$5 ] -reg byte y [ main::$0 ] -reg byte x [ main::$7 ] +reg byte a [ print::p_x#2 ] +reg byte x [ idx#11 idx#12 ] +reg byte x [ idx#4 ] FINAL ASSEMBLER -Score: 746 +Score: 46 //SEG0 File Comments -// Minimal struct - array of struct +// Minimal struct - passing struct value parameter //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" //SEG2 Global Constants & labels + .label SCREEN = $400 //SEG3 @begin //SEG4 [1] phi from @begin to @1 [phi:@begin->@1] //SEG5 @1 @@ -549,61 +601,40 @@ Score: 746 //SEG9 @end //SEG10 main main: { - .label SCREEN = $400 - .label _5 = 2 - //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] - //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + .label p1_y = 4 + //SEG11 [5] call print + //SEG12 [9] phi from main to print [phi:main->print] + //SEG13 [9] phi (byte) idx#11 = (byte) 0 [phi:main->print#0] -- vbuxx=vbuc1 ldx #0 - //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] - //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy - //SEG15 main::@1 - b1: - //SEG16 [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuxx_rol_1 - txa - asl - sta _5 - //SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuxx - tay - txa - sta points,y - //SEG18 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuyy=vbuxx_plus_1 - txa - tay - iny - //SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuyy - tya - ldy _5 - sta points+1,y - //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx - inx - //SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 - cpx #5 - bne b1 - //SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2] - //SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 - ldy #0 - //SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2] - //SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy - //SEG26 main::@2 - b2: - //SEG27 [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuxx=vbuyy_rol_1 - tya - asl - tax - //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_0 - lda points,x - sta SCREEN,y - //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_1 - lda points+1,x - sta SCREEN+$28,y - //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy - iny - //SEG31 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 -- vbuyy_neq_vbuc1_then_la1 - cpy #5 - bne b2 - //SEG32 main::@return - //SEG33 [18] return + //SEG14 [9] phi (byte) print::p_x#2 = (byte) 1 [phi:main->print#1] -- vbuaa=vbuc1 + lda #1 + jsr print + //SEG15 [6] phi from main to main::@1 [phi:main->main::@1] + //SEG16 main::@1 + //SEG17 [7] call print + //SEG18 [9] phi from main::@1 to print [phi:main::@1->print] + //SEG19 [9] phi (byte) idx#11 = (byte) idx#12 [phi:main::@1->print#0] -- register_copy + //SEG20 [9] phi (byte) print::p_x#2 = (byte) 2 [phi:main::@1->print#1] -- vbuaa=vbuc1 + lda #2 + jsr print + //SEG21 main::@return + //SEG22 [8] return + rts +} +//SEG23 print +// print(byte register(A) p_x) +print: { + //SEG24 [10] *((const byte*) SCREEN#0 + (byte) idx#11) ← (byte) print::p_x#2 -- pbuc1_derefidx_vbuxx=vbuaa + sta SCREEN,x + //SEG25 [11] (byte) idx#4 ← ++ (byte) idx#11 -- vbuxx=_inc_vbuxx + inx + //SEG26 [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (const byte) main::p1_y#1 -- pbuc1_derefidx_vbuxx=vbuc2 + lda #main.p1_y + sta SCREEN,x + //SEG27 [13] (byte) idx#12 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx + inx + //SEG28 print::@return + //SEG29 [14] return rts } - points: .fill 2*4, 0 diff --git a/src/test/ref/struct-ptr-0.asm b/src/test/ref/struct-ptr-0.asm new file mode 100644 index 000000000..998d77eb6 --- /dev/null +++ b/src/test/ref/struct-ptr-0.asm @@ -0,0 +1,39 @@ +// Minimal struct - array of struct +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .label SCREEN = $400 + .label _5 = 2 + ldx #0 + b1: + txa + asl + sta _5 + tay + txa + sta points,y + txa + tay + iny + tya + ldy _5 + sta points+1,y + inx + cpx #5 + bne b1 + ldy #0 + b2: + tya + asl + tax + lda points,x + sta SCREEN,y + lda points+1,x + sta SCREEN+$28,y + iny + cpy #5 + bne b2 + rts +} + points: .fill 2*4, 0 diff --git a/src/test/ref/struct-ptr-0.cfg b/src/test/ref/struct-ptr-0.cfg new file mode 100644 index 000000000..77cf1ccaf --- /dev/null +++ b/src/test/ref/struct-ptr-0.cfg @@ -0,0 +1,32 @@ +@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] 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 ) + [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 + [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 + [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 + [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 + [10] (byte) main::i#1 ← ++ (byte) main::i#2 + [11] if((byte) main::i#1!=(byte) 5) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [12] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) + [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 + [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x + [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y + [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 + [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@2 + [18] return + to:@return diff --git a/src/test/ref/struct-ptr-0.log b/src/test/ref/struct-ptr-0.log new file mode 100644 index 000000000..5d7f09b74 --- /dev/null +++ b/src/test/ref/struct-ptr-0.log @@ -0,0 +1,609 @@ +Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i) +Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i) +Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i1) +Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i1) +Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 +Culled Empty Block (label) main::@4 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (struct Point[4]) points#0 ← { fill( 4, 0) } + to:@1 +main: scope:[main] from @1 + (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~) main::$4 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT + *((struct Point[4]) points#0 + (byte~) main::$4).x ← (byte) main::i#2 + (number~) main::$0 ← (byte) main::i#2 + (number) 1 + (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT + *((struct Point[4]) points#0 + (byte~) main::$5).y ← (number~) main::$0 + (byte) main::i#1 ← (byte) main::i#2 + rangenext(0,4) + (bool~) main::$1 ← (byte) main::i#1 != rangelast(0,4) + if((bool~) main::$1) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 + (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 + (byte) main::i1#0 ← (byte) 0 + to:main::@3 +main::@3: scope:[main] from main::@2 main::@3 + (byte) main::i1#2 ← phi( main::@2/(byte) main::i1#0 main::@3/(byte) main::i1#1 ) + (byte~) main::$6 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT + *((byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((struct Point[4]) points#0 + (byte~) main::$6).x + (byte*~) main::$2 ← (byte*) main::SCREEN#0 + (number) $28 + (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT + *((byte*~) main::$2 + (byte) main::i1#2) ← *((struct Point[4]) points#0 + (byte~) main::$7).y + (byte) main::i1#1 ← (byte) main::i1#2 + rangenext(0,4) + (bool~) main::$3 ← (byte) main::i1#1 != rangelast(0,4) + if((bool~) main::$3) goto main::@3 + to:main::@return +main::@return: scope:[main] from main::@3 + 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 +(byte) Point::x +(byte) Point::y +(const byte) SIZEOF_STRUCT_POINT = (byte) 2 +(void()) main() +(number~) main::$0 +(bool~) main::$1 +(byte*~) main::$2 +(bool~) main::$3 +(byte~) main::$4 +(byte~) main::$5 +(byte~) main::$6 +(byte~) main::$7 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(byte) main::i1 +(byte) main::i1#0 +(byte) main::i1#1 +(byte) main::i1#2 +(struct Point[4]) points +(struct Point[4]) points#0 + +Adding number conversion cast (unumber) 1 in (number~) main::$0 ← (byte) main::i#2 + (number) 1 +Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (byte) main::i#2 + (unumber)(number) 1 +Adding number conversion cast (unumber) $28 in (byte*~) main::$2 ← (byte*) main::SCREEN#0 + (number) $28 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast 1 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast $28 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) $28 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inferred type updated to byte in (unumber~) main::$0 ← (byte) main::i#2 + (byte) 1 +Identified duplicate assignment right side [6] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT +Identified duplicate assignment right side [17] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization Pass2DuplicateRValueIdentification +Simple Condition (bool~) main::$1 [10] if((byte) main::i#1!=rangelast(0,4)) goto main::@1 +Simple Condition (bool~) main::$3 [21] if((byte) main::i1#1!=rangelast(0,4)) goto main::@3 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant right-side identified [0] (struct Point[4]) points#0 ← { fill( 4, 0) } +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const struct Point[4]) points#0 = { fill( 4, 0) } +Constant (const byte) main::i#0 = 0 +Constant (const byte*) main::SCREEN#0 = (byte*) 1024 +Constant (const byte) main::i1#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Resolved ranged next value [8] main::i#1 ← ++ main::i#2 to ++ +Resolved ranged comparison value [10] if(main::i#1!=rangelast(0,4)) goto main::@1 to (number) 5 +Resolved ranged next value [19] main::i1#1 ← ++ main::i1#2 to ++ +Resolved ranged comparison value [21] if(main::i1#1!=rangelast(0,4)) goto main::@3 to (number) 5 +Adding number conversion cast (unumber) 5 in if((byte) main::i#1!=(number) 5) goto main::@1 +Adding number conversion cast (unumber) 5 in if((byte) main::i1#1!=(number) 5) goto main::@3 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant integer cast 5 +Simplifying constant integer cast 5 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 5 +Finalized unsigned number type (byte) 5 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (byte~) main::$5 = (byte~) main::$4 +Alias (byte~) main::$7 = (byte~) main::$6 +Successful SSA optimization Pass2AliasElimination +Constant right-side identified [11] (byte*~) main::$2 ← (const byte*) main::SCREEN#0 + (byte) $28 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::$2 = main::SCREEN#0+$28 +Successful SSA optimization Pass2ConstantIdentification +Rewriting multiplication to use shift [1] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT +Rewriting multiplication to use shift [8] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization Pass2MultiplyToShiftRewriting +Inlining constant with var siblings (const byte) main::i#0 +Inlining constant with var siblings (const byte) main::i1#0 +Constant inlined main::i#0 = (byte) 0 +Constant inlined main::i1#0 = (byte) 0 +Constant inlined main::$2 = (const byte*) main::SCREEN#0+(byte) $28 +Successful SSA optimization Pass2ConstantInlining +Eliminating unused constant (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization PassNEliminateUnusedVars +Added new block during phi lifting main::@5(between main::@1 and main::@1) +Added new block during phi lifting main::@6(between main::@3 and main::@3) +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 +Adding NOP phi() at start of main::@2 +CALL GRAPH +Calls in [] to main:2 + +Created 2 initial phi equivalence classes +Coalesced [21] main::i1#3 ← main::i1#1 +Coalesced [22] main::i#3 ← main::i#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) @2 +Culled Empty Block (label) main::@2 +Culled Empty Block (label) main::@6 +Culled Empty Block (label) main::@5 +Renumbering block main::@3 to main::@2 +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() + 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] 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 ) + [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 + [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 + [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 + [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 + [10] (byte) main::i#1 ← ++ (byte) main::i#2 + [11] if((byte) main::i#1!=(byte) 5) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [12] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) + [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 + [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x + [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y + [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 + [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@2 + [18] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte) Point::x +(byte) Point::y +(void()) main() +(byte~) main::$0 22.0 +(byte~) main::$5 3.6666666666666665 +(byte~) main::$7 5.5 +(byte*) main::SCREEN +(byte) main::i +(byte) main::i#1 16.5 +(byte) main::i#2 11.0 +(byte) main::i1 +(byte) main::i1#1 16.5 +(byte) main::i1#2 13.75 +(struct Point[4]) points + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +[ main::i1#2 main::i1#1 ] +Added variable main::$5 to zero page equivalence class [ main::$5 ] +Added variable main::$0 to zero page equivalence class [ main::$0 ] +Added variable main::$7 to zero page equivalence class [ main::$7 ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ main::i1#2 main::i1#1 ] +[ main::$5 ] +[ main::$0 ] +[ main::$7 ] +Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Allocated zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Allocated zp ZP_BYTE:4 [ main::$5 ] +Allocated zp ZP_BYTE:5 [ main::$0 ] +Allocated zp ZP_BYTE:6 [ main::$7 ] + +INITIAL ASM +//SEG0 File Comments +// Minimal struct - array of struct +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//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 +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + .label _0 = 5 + .label _5 = 4 + .label _7 = 6 + .label i = 2 + .label i1 = 3 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta i + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda i + asl + sta _5 + //SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuz2 + lda i + ldy _5 + sta points,y + //SEG18 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuz1=vbuz2_plus_1 + ldy i + iny + sty _0 + //SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuz2 + lda _0 + ldy _5 + sta points+1,y + //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc i + //SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 + lda #5 + cmp i + bne b1_from_b1 + //SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 + lda #0 + sta i1 + jmp b2 + //SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy + jmp b2 + //SEG26 main::@2 + b2: + //SEG27 [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda i1 + asl + sta _7 + //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuz1=pssc2_derefidx_vbuz2_mbr_0 + ldx _7 + lda points,x + ldx i1 + sta SCREEN,x + //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuz1=pssc2_derefidx_vbuz2_mbr_1 + ldx _7 + lda points+1,x + ldx i1 + sta SCREEN+$28,x + //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1 + inc i1 + //SEG31 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 -- vbuz1_neq_vbuc1_then_la1 + lda #5 + cmp i1 + bne b2_from_b2 + jmp breturn + //SEG32 main::@return + breturn: + //SEG33 [18] return + rts +} + points: .fill 2*4, 0 + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) 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 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::$5 ] +Statement [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ main::$7 ] +Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a +Statement [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a +Statement [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a +Statement [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a +Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a +Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y [ main::i1#2 ] ( main:2 [ main::i1#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 , +Potential registers zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:4 [ main::$5 ] : zp ZP_BYTE:4 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:5 [ main::$0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:6 [ main::$7 ] : zp ZP_BYTE:6 , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 30.25: zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] 27.5: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:5 [ main::$0 ] 5.5: zp ZP_BYTE:6 [ main::$7 ] 3.67: zp ZP_BYTE:4 [ main::$5 ] +Uplift Scope [Point] +Uplift Scope [] + +Uplifting [main] best 918 combination reg byte y [ main::i1#2 main::i1#1 ] reg byte x [ main::i#2 main::i#1 ] reg byte y [ main::$0 ] reg byte x [ main::$7 ] zp ZP_BYTE:4 [ main::$5 ] +Limited combination testing to 100 combinations of 324 possible. +Uplifting [Point] best 918 combination +Uplifting [] best 918 combination +Attempting to uplift remaining variables inzp ZP_BYTE:4 [ main::$5 ] +Uplifting [main] best 918 combination zp ZP_BYTE:4 [ main::$5 ] +Allocated (was zp ZP_BYTE:4) zp ZP_BYTE:2 [ main::$5 ] + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Minimal struct - array of struct +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//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 +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + .label _5 = 2 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuxx_rol_1 + txa + asl + sta _5 + //SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuxx + ldy _5 + txa + sta points,y + //SEG18 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuyy=vbuxx_plus_1 + txa + tay + iny + //SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuyy + tya + ldy _5 + sta points+1,y + //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + //SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #5 + bne b1_from_b1 + //SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + jmp b2 + //SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy + jmp b2 + //SEG26 main::@2 + b2: + //SEG27 [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuxx=vbuyy_rol_1 + tya + asl + tax + //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_0 + lda points,x + sta SCREEN,y + //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_1 + lda points+1,x + sta SCREEN+$28,y + //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy + iny + //SEG31 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 -- vbuyy_neq_vbuc1_then_la1 + cpy #5 + bne b2_from_b2 + jmp breturn + //SEG32 main::@return + breturn: + //SEG33 [18] return + rts +} + points: .fill 2*4, 0 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing instruction ldy _5 with TAY +Replacing label b1_from_b1 with b1 +Replacing label b2_from_b2 with b2 +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_b1: +Removing instruction b2_from_b2: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b2_from_b1: +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 +Removing instruction jmp b2 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(byte) Point::x +(byte) Point::y +(void()) main() +(byte~) main::$0 reg byte y 22.0 +(byte~) main::$5 $5 zp ZP_BYTE:2 3.6666666666666665 +(byte~) main::$7 reg byte x 5.5 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 11.0 +(byte) main::i1 +(byte) main::i1#1 reg byte y 16.5 +(byte) main::i1#2 reg byte y 13.75 +(struct Point[4]) points +(const struct Point[4]) points#0 points = { fill( 4, 0) } + +reg byte x [ main::i#2 main::i#1 ] +reg byte y [ main::i1#2 main::i1#1 ] +zp ZP_BYTE:2 [ main::$5 ] +reg byte y [ main::$0 ] +reg byte x [ main::$7 ] + + +FINAL ASSEMBLER +Score: 746 + +//SEG0 File Comments +// Minimal struct - array of struct +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG9 @end +//SEG10 main +main: { + .label SCREEN = $400 + .label _5 = 2 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuxx_rol_1 + txa + asl + sta _5 + //SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuxx + tay + txa + sta points,y + //SEG18 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuyy=vbuxx_plus_1 + txa + tay + iny + //SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuyy + tya + ldy _5 + sta points+1,y + //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + //SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #5 + bne b1 + //SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + //SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + //SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy + //SEG26 main::@2 + b2: + //SEG27 [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuxx=vbuyy_rol_1 + tya + asl + tax + //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_0 + lda points,x + sta SCREEN,y + //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_1 + lda points+1,x + sta SCREEN+$28,y + //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy + iny + //SEG31 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 -- vbuyy_neq_vbuc1_then_la1 + cpy #5 + bne b2 + //SEG32 main::@return + //SEG33 [18] return + rts +} + points: .fill 2*4, 0 + diff --git a/src/test/ref/struct-ptr-0.sym b/src/test/ref/struct-ptr-0.sym new file mode 100644 index 000000000..1daabbadc --- /dev/null +++ b/src/test/ref/struct-ptr-0.sym @@ -0,0 +1 @@ +program \ No newline at end of file diff --git a/src/test/ref/struct-ptr-1.asm b/src/test/ref/struct-ptr-1.asm new file mode 100644 index 000000000..13f78da1c --- /dev/null +++ b/src/test/ref/struct-ptr-1.asm @@ -0,0 +1,38 @@ +// Minimal struct - array of struct - near pointer math indexing +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const OFFS_Y = 1 +main: { + .label SCREEN = $400 + ldx #0 + b1: + txa + asl + tay + txa + sta points,y + txa + clc + adc #4 + // points[i].x = i; + sta points+OFFS_Y,y + inx + cpx #4 + bne b1 + ldy #0 + b2: + tya + asl + tax + lda points,x + sta SCREEN,y + // SCREEN[i] = points[i].x; + lda points+OFFS_Y,x + sta SCREEN+$28,y + iny + cpy #4 + bne b2 + rts +} + points: .fill 2*4, 0 diff --git a/src/test/ref/struct-ptr-1.cfg b/src/test/ref/struct-ptr-1.cfg new file mode 100644 index 000000000..f4dc21802 --- /dev/null +++ b/src/test/ref/struct-ptr-1.cfg @@ -0,0 +1,32 @@ +@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] 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 ) + [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 + [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 + [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 + [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$6) ← (byte~) main::$8 + [10] (byte) main::i#1 ← ++ (byte) main::i#2 + [11] if((byte) main::i#1!=(byte) 4) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [12] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) + [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 + [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) + [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) + [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 + [17] if((byte) main::i1#1!=(byte) 4) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@2 + [18] return + to:@return diff --git a/src/test/ref/struct-ptr-1.log b/src/test/ref/struct-ptr-1.log new file mode 100644 index 000000000..41687bb83 --- /dev/null +++ b/src/test/ref/struct-ptr-1.log @@ -0,0 +1,701 @@ +Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 +Culled Empty Block (label) main::@4 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (struct Point[4]) points#0 ← { fill( 4, 0) } + (byte) SIZEOF_POINT#0 ← (number) 2 + (byte) OFFS_X#0 ← (number) 0 + (byte) OFFS_Y#0 ← (number) 1 + to:@1 +main: scope:[main] from @1 + (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*~) main::$0 ← ((byte*)) (struct Point[4]) points#0 + (byte*~) main::$1 ← (byte*~) main::$0 + (byte) OFFS_X#0 + (byte~) main::$2 ← (byte) main::i#2 * (byte) SIZEOF_POINT#0 + (byte*~) main::$3 ← (byte*~) main::$1 + (byte~) main::$2 + *((byte*~) main::$3) ← (byte) main::i#2 + (byte*~) main::$4 ← ((byte*)) (struct Point[4]) points#0 + (byte*~) main::$5 ← (byte*~) main::$4 + (byte) OFFS_Y#0 + (byte~) main::$6 ← (byte) main::i#2 * (byte) SIZEOF_POINT#0 + (byte*~) main::$7 ← (byte*~) main::$5 + (byte~) main::$6 + (number~) main::$8 ← (byte) main::i#2 + (number) 4 + *((byte*~) main::$7) ← (number~) main::$8 + (byte) main::i#1 ← (byte) main::i#2 + rangenext(0,3) + (bool~) main::$9 ← (byte) main::i#1 != rangelast(0,3) + if((bool~) main::$9) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 + (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 + (byte) main::i1#0 ← (byte) 0 + to:main::@3 +main::@3: scope:[main] from main::@2 main::@3 + (byte) main::i1#2 ← phi( main::@2/(byte) main::i1#0 main::@3/(byte) main::i1#1 ) + (byte*~) main::$10 ← ((byte*)) (struct Point[4]) points#0 + (byte*~) main::$11 ← (byte*~) main::$10 + (byte) OFFS_X#0 + (byte~) main::$12 ← (byte) main::i1#2 * (byte) SIZEOF_POINT#0 + (byte*~) main::$13 ← (byte*~) main::$11 + (byte~) main::$12 + *((byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$13) + (byte*~) main::$14 ← (byte*) main::SCREEN#0 + (number) $28 + (byte*~) main::$15 ← ((byte*)) (struct Point[4]) points#0 + (byte*~) main::$16 ← (byte*~) main::$15 + (byte) OFFS_Y#0 + (byte~) main::$17 ← (byte) main::i1#2 * (byte) SIZEOF_POINT#0 + (byte*~) main::$18 ← (byte*~) main::$16 + (byte~) main::$17 + *((byte*~) main::$14 + (byte) main::i1#2) ← *((byte*~) main::$18) + (byte) main::i1#1 ← (byte) main::i1#2 + rangenext(0,3) + (bool~) main::$19 ← (byte) main::i1#1 != rangelast(0,3) + if((bool~) main::$19) goto main::@3 + to:main::@return +main::@return: scope:[main] from main::@3 + 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 +(byte) OFFS_X +(byte) OFFS_X#0 +(byte) OFFS_Y +(byte) OFFS_Y#0 +(byte) Point::x +(byte) Point::y +(byte) SIZEOF_POINT +(byte) SIZEOF_POINT#0 +(void()) main() +(byte*~) main::$0 +(byte*~) main::$1 +(byte*~) main::$10 +(byte*~) main::$11 +(byte~) main::$12 +(byte*~) main::$13 +(byte*~) main::$14 +(byte*~) main::$15 +(byte*~) main::$16 +(byte~) main::$17 +(byte*~) main::$18 +(bool~) main::$19 +(byte~) main::$2 +(byte*~) main::$3 +(byte*~) main::$4 +(byte*~) main::$5 +(byte~) main::$6 +(byte*~) main::$7 +(number~) main::$8 +(bool~) main::$9 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(byte) main::i1 +(byte) main::i1#0 +(byte) main::i1#1 +(byte) main::i1#2 +(struct Point[4]) points +(struct Point[4]) points#0 + +Adding number conversion cast (unumber) 2 in (byte) SIZEOF_POINT#0 ← (number) 2 +Adding number conversion cast (unumber) 0 in (byte) OFFS_X#0 ← (number) 0 +Adding number conversion cast (unumber) 1 in (byte) OFFS_Y#0 ← (number) 1 +Adding number conversion cast (unumber) 4 in (number~) main::$8 ← (byte) main::i#2 + (number) 4 +Adding number conversion cast (unumber) main::$8 in (number~) main::$8 ← (byte) main::i#2 + (unumber)(number) 4 +Adding number conversion cast (unumber) $28 in (byte*~) main::$14 ← (byte*) main::SCREEN#0 + (number) $28 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte) SIZEOF_POINT#0 ← (unumber)(number) 2 +Inlining cast (byte) OFFS_X#0 ← (unumber)(number) 0 +Inlining cast (byte) OFFS_Y#0 ← (unumber)(number) 1 +Inlining cast (byte*~) main::$0 ← (byte*)(struct Point[4]) points#0 +Inlining cast (byte*~) main::$4 ← (byte*)(struct Point[4]) points#0 +Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 +Inlining cast (byte*~) main::$10 ← (byte*)(struct Point[4]) points#0 +Inlining cast (byte*~) main::$15 ← (byte*)(struct Point[4]) points#0 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast 2 +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 +Simplifying constant integer cast 4 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast $28 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 4 +Finalized unsigned number type (byte) $28 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inferred type updated to byte in (unumber~) main::$8 ← (byte) main::i#2 + (byte) 4 +Identified duplicate assignment right side [13] (byte~) main::$6 ← (byte) main::i#2 * (byte) SIZEOF_POINT#0 +Identified duplicate assignment right side [31] (byte~) main::$17 ← (byte) main::i1#2 * (byte) SIZEOF_POINT#0 +Successful SSA optimization Pass2DuplicateRValueIdentification +Simple Condition (bool~) main::$9 [19] if((byte) main::i#1!=rangelast(0,3)) goto main::@1 +Simple Condition (bool~) main::$19 [36] if((byte) main::i1#1!=rangelast(0,3)) goto main::@3 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant right-side identified [0] (struct Point[4]) points#0 ← { fill( 4, 0) } +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const struct Point[4]) points#0 = { fill( 4, 0) } +Constant (const byte) SIZEOF_POINT#0 = 2 +Constant (const byte) OFFS_X#0 = 0 +Constant (const byte) OFFS_Y#0 = 1 +Constant (const byte) main::i#0 = 0 +Constant (const byte*) main::SCREEN#0 = (byte*) 1024 +Constant (const byte) main::i1#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Constant value identified (byte*)points#0 in [6] (byte*~) main::$0 ← (byte*)(const struct Point[4]) points#0 +Constant value identified (byte*)points#0 in [11] (byte*~) main::$4 ← (byte*)(const struct Point[4]) points#0 +Constant value identified (byte*)points#0 in [23] (byte*~) main::$10 ← (byte*)(const struct Point[4]) points#0 +Constant value identified (byte*)points#0 in [29] (byte*~) main::$15 ← (byte*)(const struct Point[4]) points#0 +Successful SSA optimization Pass2ConstantValues +Resolved ranged next value [17] main::i#1 ← ++ main::i#2 to ++ +Resolved ranged comparison value [19] if(main::i#1!=rangelast(0,3)) goto main::@1 to (number) 4 +Resolved ranged next value [34] main::i1#1 ← ++ main::i1#2 to ++ +Resolved ranged comparison value [36] if(main::i1#1!=rangelast(0,3)) goto main::@3 to (number) 4 +Converting *(pointer+n) to pointer[n] [10] *((byte*~) main::$3) ← (byte) main::i#2 -- *(main::$1 + main::$2) +Converting *(pointer+n) to pointer[n] [16] *((byte*~) main::$7) ← (byte~) main::$8 -- *(main::$5 + main::$6) +Converting *(pointer+n) to pointer[n] [27] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$13) -- *(main::$11 + main::$12) +Converting *(pointer+n) to pointer[n] [33] *((byte*~) main::$14 + (byte) main::i1#2) ← *((byte*~) main::$18) -- *(main::$16 + main::$17) +Successful SSA optimization Pass2InlineDerefIdx +Simplifying expression containing zero main::$0 in [7] (byte*~) main::$1 ← (byte*~) main::$0 + (const byte) OFFS_X#0 +Simplifying expression containing zero main::$10 in [24] (byte*~) main::$11 ← (byte*~) main::$10 + (const byte) OFFS_X#0 +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused variable (byte*~) main::$3 and assignment [4] (byte*~) main::$3 ← (byte*~) main::$1 + (byte~) main::$2 +Eliminating unused variable (byte*~) main::$7 and assignment [9] (byte*~) main::$7 ← (byte*~) main::$5 + (byte~) main::$6 +Eliminating unused variable (byte*~) main::$13 and assignment [18] (byte*~) main::$13 ← (byte*~) main::$11 + (byte~) main::$12 +Eliminating unused variable (byte*~) main::$18 and assignment [24] (byte*~) main::$18 ← (byte*~) main::$16 + (byte~) main::$17 +Eliminating unused constant (const byte) OFFS_X#0 +Successful SSA optimization PassNEliminateUnusedVars +Adding number conversion cast (unumber) 4 in if((byte) main::i#1!=(number) 4) goto main::@1 +Adding number conversion cast (unumber) 4 in if((byte) main::i1#1!=(number) 4) goto main::@3 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant integer cast 4 +Simplifying constant integer cast 4 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 4 +Finalized unsigned number type (byte) 4 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (byte*~) main::$1 = (byte*~) main::$0 +Alias (byte~) main::$6 = (byte~) main::$2 +Alias (byte*~) main::$11 = (byte*~) main::$10 +Alias (byte~) main::$17 = (byte~) main::$12 +Successful SSA optimization Pass2AliasElimination +Constant right-side identified [17] (byte*~) main::$14 ← (const byte*) main::SCREEN#0 + (byte) $28 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::$1 = (byte*)points#0 +Constant (const byte*) main::$4 = (byte*)points#0 +Constant (const byte*) main::$11 = (byte*)points#0 +Constant (const byte*) main::$14 = main::SCREEN#0+$28 +Constant (const byte*) main::$15 = (byte*)points#0 +Successful SSA optimization Pass2ConstantIdentification +Constant right-side identified [3] (byte*~) main::$5 ← (const byte*) main::$4 + (const byte) OFFS_Y#0 +Constant right-side identified [11] (byte*~) main::$16 ← (const byte*) main::$15 + (const byte) OFFS_Y#0 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::$5 = main::$4+OFFS_Y#0 +Constant (const byte*) main::$16 = main::$15+OFFS_Y#0 +Successful SSA optimization Pass2ConstantIdentification +Rewriting multiplication to use shift [1] (byte~) main::$6 ← (byte) main::i#2 * (const byte) SIZEOF_POINT#0 +Rewriting multiplication to use shift [8] (byte~) main::$17 ← (byte) main::i1#2 * (const byte) SIZEOF_POINT#0 +Successful SSA optimization Pass2MultiplyToShiftRewriting +Inlining constant with var siblings (const byte) main::i#0 +Inlining constant with var siblings (const byte) main::i1#0 +Constant inlined main::$1 = (byte*)(const struct Point[4]) points#0 +Constant inlined main::$16 = (byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 +Constant inlined main::$5 = (byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 +Constant inlined main::i#0 = (byte) 0 +Constant inlined main::i1#0 = (byte) 0 +Constant inlined main::$14 = (const byte*) main::SCREEN#0+(byte) $28 +Constant inlined main::$4 = (byte*)(const struct Point[4]) points#0 +Constant inlined main::$15 = (byte*)(const struct Point[4]) points#0 +Constant inlined main::$11 = (byte*)(const struct Point[4]) points#0 +Successful SSA optimization Pass2ConstantInlining +Eliminating unused constant (const byte) SIZEOF_POINT#0 +Successful SSA optimization PassNEliminateUnusedVars +Added new block during phi lifting main::@5(between main::@1 and main::@1) +Added new block during phi lifting main::@6(between main::@3 and main::@3) +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 +Adding NOP phi() at start of main::@2 +CALL GRAPH +Calls in [] to main:2 + +Created 2 initial phi equivalence classes +Coalesced [21] main::i1#3 ← main::i1#1 +Coalesced [22] main::i#3 ← main::i#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) @2 +Culled Empty Block (label) main::@2 +Culled Empty Block (label) main::@6 +Culled Empty Block (label) main::@5 +Renumbering block main::@3 to main::@2 +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() + 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] 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 ) + [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 + [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 + [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 + [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$6) ← (byte~) main::$8 + [10] (byte) main::i#1 ← ++ (byte) main::i#2 + [11] if((byte) main::i#1!=(byte) 4) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [12] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) + [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 + [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) + [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) + [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 + [17] if((byte) main::i1#1!=(byte) 4) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@2 + [18] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte) OFFS_X +(byte) OFFS_Y +(byte) Point::x +(byte) Point::y +(byte) SIZEOF_POINT +(void()) main() +(byte~) main::$17 16.5 +(byte~) main::$6 11.0 +(byte~) main::$8 22.0 +(byte*) main::SCREEN +(byte) main::i +(byte) main::i#1 16.5 +(byte) main::i#2 11.0 +(byte) main::i1 +(byte) main::i1#1 16.5 +(byte) main::i1#2 13.75 +(struct Point[4]) points + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +[ main::i1#2 main::i1#1 ] +Added variable main::$6 to zero page equivalence class [ main::$6 ] +Added variable main::$8 to zero page equivalence class [ main::$8 ] +Added variable main::$17 to zero page equivalence class [ main::$17 ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ main::i1#2 main::i1#1 ] +[ main::$6 ] +[ main::$8 ] +[ main::$17 ] +Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Allocated zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Allocated zp ZP_BYTE:4 [ main::$6 ] +Allocated zp ZP_BYTE:5 [ main::$8 ] +Allocated zp ZP_BYTE:6 [ main::$17 ] + +INITIAL ASM +//SEG0 File Comments +// Minimal struct - array of struct - near pointer math indexing +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFS_Y = 1 +//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 +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + .label _6 = 4 + .label _8 = 5 + .label _17 = 6 + .label i = 2 + .label i1 = 3 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta i + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda i + asl + sta _6 + //SEG17 [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 -- pbuc1_derefidx_vbuz1=vbuz2 + lda i + ldy _6 + sta points,y + //SEG18 [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 -- vbuz1=vbuz2_plus_vbuc1 + lax i + axs #-[4] + stx _8 + //SEG19 [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$6) ← (byte~) main::$8 -- pbuc1_derefidx_vbuz1=vbuz2 + // points[i].x = i; + lda _8 + ldy _6 + sta points+OFFS_Y,y + //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc i + //SEG21 [11] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 + lda #4 + cmp i + bne b1_from_b1 + //SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 + lda #0 + sta i1 + jmp b2 + //SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy + jmp b2 + //SEG26 main::@2 + b2: + //SEG27 [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda i1 + asl + sta _17 + //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2 + ldy _17 + lda points,y + ldy i1 + sta SCREEN,y + //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2 + // SCREEN[i] = points[i].x; + ldy _17 + lda points+OFFS_Y,y + ldy i1 + sta SCREEN+$28,y + //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1 + inc i1 + //SEG31 [17] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuz1_neq_vbuc1_then_la1 + lda #4 + cmp i1 + bne b2_from_b2 + jmp breturn + //SEG32 main::@return + breturn: + //SEG33 [18] return + rts +} + points: .fill 2*4, 0 + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$6 ] ( main:2 [ main::i#2 main::$6 ] ) 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 [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 [ main::i#2 main::$6 ] ( main:2 [ main::i#2 main::$6 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::$6 ] +Statement [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 [ main::i#2 main::$6 main::$8 ] ( main:2 [ main::i#2 main::$6 main::$8 ] ) always clobbers reg byte a +Statement [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$17 ] ( main:2 [ main::i1#2 main::$17 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) [ main::i1#2 main::$17 ] ( main:2 [ main::i1#2 main::$17 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ main::$17 ] +Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a +Statement [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$6 ] ( main:2 [ main::i#2 main::$6 ] ) always clobbers reg byte a +Statement [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 [ main::i#2 main::$6 ] ( main:2 [ main::i#2 main::$6 ] ) always clobbers reg byte a +Statement [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 [ main::i#2 main::$6 main::$8 ] ( main:2 [ main::i#2 main::$6 main::$8 ] ) always clobbers reg byte a +Statement [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$17 ] ( main:2 [ main::i1#2 main::$17 ] ) always clobbers reg byte a +Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) [ main::i1#2 main::$17 ] ( main:2 [ main::i1#2 main::$17 ] ) always clobbers reg byte a +Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) [ main::i1#2 ] ( main:2 [ main::i1#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 , +Potential registers zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:4 [ main::$6 ] : zp ZP_BYTE:4 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:5 [ main::$8 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:6 [ main::$17 ] : zp ZP_BYTE:6 , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 30.25: zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] 27.5: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:5 [ main::$8 ] 16.5: zp ZP_BYTE:6 [ main::$17 ] 11: zp ZP_BYTE:4 [ main::$6 ] +Uplift Scope [Point] +Uplift Scope [] + +Uplifting [main] best 898 combination reg byte y [ main::i1#2 main::i1#1 ] reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$8 ] reg byte x [ main::$17 ] zp ZP_BYTE:4 [ main::$6 ] +Limited combination testing to 100 combinations of 324 possible. +Uplifting [Point] best 898 combination +Uplifting [] best 898 combination +Attempting to uplift remaining variables inzp ZP_BYTE:4 [ main::$6 ] +Uplifting [main] best 828 combination reg byte y [ main::$6 ] + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Minimal struct - array of struct - near pointer math indexing +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFS_Y = 1 +//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 +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuxx_rol_1 + txa + asl + tay + //SEG17 [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 -- pbuc1_derefidx_vbuyy=vbuxx + txa + sta points,y + //SEG18 [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 -- vbuaa=vbuxx_plus_vbuc1 + txa + clc + adc #4 + //SEG19 [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$6) ← (byte~) main::$8 -- pbuc1_derefidx_vbuyy=vbuaa + // points[i].x = i; + sta points+OFFS_Y,y + //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + //SEG21 [11] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #4 + bne b1_from_b1 + //SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + jmp b2 + //SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy + jmp b2 + //SEG26 main::@2 + b2: + //SEG27 [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 -- vbuxx=vbuyy_rol_1 + tya + asl + tax + //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx + lda points,x + sta SCREEN,y + //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx + // SCREEN[i] = points[i].x; + lda points+OFFS_Y,x + sta SCREEN+$28,y + //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy + iny + //SEG31 [17] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuyy_neq_vbuc1_then_la1 + cpy #4 + bne b2_from_b2 + jmp breturn + //SEG32 main::@return + breturn: + //SEG33 [18] return + rts +} + points: .fill 2*4, 0 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing label b1_from_b1 with b1 +Replacing label b2_from_b2 with b2 +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_b1: +Removing instruction b2_from_b2: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b2_from_b1: +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 +Removing instruction jmp b2 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(byte) OFFS_X +(byte) OFFS_Y +(const byte) OFFS_Y#0 OFFS_Y = (byte) 1 +(byte) Point::x +(byte) Point::y +(byte) SIZEOF_POINT +(void()) main() +(byte~) main::$17 reg byte x 16.5 +(byte~) main::$6 reg byte y 11.0 +(byte~) main::$8 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 11.0 +(byte) main::i1 +(byte) main::i1#1 reg byte y 16.5 +(byte) main::i1#2 reg byte y 13.75 +(struct Point[4]) points +(const struct Point[4]) points#0 points = { fill( 4, 0) } + +reg byte x [ main::i#2 main::i#1 ] +reg byte y [ main::i1#2 main::i1#1 ] +reg byte y [ main::$6 ] +reg byte a [ main::$8 ] +reg byte x [ main::$17 ] + + +FINAL ASSEMBLER +Score: 666 + +//SEG0 File Comments +// Minimal struct - array of struct - near pointer math indexing +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFS_Y = 1 +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG9 @end +//SEG10 main +main: { + .label SCREEN = $400 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuxx_rol_1 + txa + asl + tay + //SEG17 [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 -- pbuc1_derefidx_vbuyy=vbuxx + txa + sta points,y + //SEG18 [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 -- vbuaa=vbuxx_plus_vbuc1 + txa + clc + adc #4 + //SEG19 [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$6) ← (byte~) main::$8 -- pbuc1_derefidx_vbuyy=vbuaa + // points[i].x = i; + sta points+OFFS_Y,y + //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + //SEG21 [11] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #4 + bne b1 + //SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + //SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + //SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy + //SEG26 main::@2 + b2: + //SEG27 [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 -- vbuxx=vbuyy_rol_1 + tya + asl + tax + //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx + lda points,x + sta SCREEN,y + //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx + // SCREEN[i] = points[i].x; + lda points+OFFS_Y,x + sta SCREEN+$28,y + //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy + iny + //SEG31 [17] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuyy_neq_vbuc1_then_la1 + cpy #4 + bne b2 + //SEG32 main::@return + //SEG33 [18] return + rts +} + points: .fill 2*4, 0 + diff --git a/src/test/ref/struct-ptr-1.sym b/src/test/ref/struct-ptr-1.sym new file mode 100644 index 000000000..1daabbadc --- /dev/null +++ b/src/test/ref/struct-ptr-1.sym @@ -0,0 +1 @@ +program \ No newline at end of file diff --git a/src/test/ref/struct-ptr-2.asm b/src/test/ref/struct-ptr-2.asm new file mode 100644 index 000000000..f63b1f446 --- /dev/null +++ b/src/test/ref/struct-ptr-2.asm @@ -0,0 +1,56 @@ +// Minimal struct - array of struct - far pointer math indexing +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const OFFS_Y = 1 +main: { + .label SCREEN = $400 + .label point_i = 2 + .label point_i1 = 4 + ldx #0 + b1: + txa + asl + tay + tya + clc + adc #points + adc #0 + sta point_i+1 + txa + sta points,y + txa + clc + adc #4 + // points[i].x = i; + ldy #OFFS_Y + sta (point_i),y + inx + cpx #4 + bne b1 + ldx #0 + b2: + txa + asl + tay + tya + clc + adc #points + adc #0 + sta point_i1+1 + lda points,y + sta SCREEN,x + // SCREEN[i] = points[i].x; + ldy #OFFS_Y + lda (point_i1),y + sta SCREEN+$28,x + inx + cpx #4 + bne b2 + rts +} + points: .fill 2*4, 0 diff --git a/src/test/ref/struct-ptr-2.cfg b/src/test/ref/struct-ptr-2.cfg new file mode 100644 index 000000000..6b2d4a012 --- /dev/null +++ b/src/test/ref/struct-ptr-2.cfg @@ -0,0 +1,34 @@ +@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] 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 ) + [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 + [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 + [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 + [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 + [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 + [11] (byte) main::i#1 ← ++ (byte) main::i#2 + [12] if((byte) main::i#1!=(byte) 4) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [13] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) + [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 + [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 + [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) + [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) + [18] (byte) main::i1#1 ← ++ (byte) main::i1#2 + [19] if((byte) main::i1#1!=(byte) 4) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@2 + [20] return + to:@return diff --git a/src/test/ref/struct-ptr-2.log b/src/test/ref/struct-ptr-2.log new file mode 100644 index 000000000..39fb49656 --- /dev/null +++ b/src/test/ref/struct-ptr-2.log @@ -0,0 +1,768 @@ +Fixing pointer addition (struct Point*~) main::$0 ← (struct Point[4]) points + (byte) main::i +Fixing pointer addition (struct Point*~) main::$7 ← (struct Point[4]) points + (byte) main::i1 +Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 +Culled Empty Block (label) main::@4 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (struct Point[4]) points#0 ← { fill( 4, 0) } + (byte) OFFS_X#0 ← (number) 0 + (byte) OFFS_Y#0 ← (number) 1 + to:@1 +main: scope:[main] from @1 + (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~) main::$14 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT + (struct Point*~) main::$0 ← (struct Point[4]) points#0 + (byte~) main::$14 + (struct Point*) main::point_i#0 ← (struct Point*~) main::$0 + (byte*~) main::$1 ← ((byte*)) (struct Point*) main::point_i#0 + (byte*~) main::$2 ← (byte*~) main::$1 + (byte) OFFS_X#0 + *((byte*~) main::$2) ← (byte) main::i#2 + (byte*~) main::$3 ← ((byte*)) (struct Point*) main::point_i#0 + (byte*~) main::$4 ← (byte*~) main::$3 + (byte) OFFS_Y#0 + (number~) main::$5 ← (byte) main::i#2 + (number) 4 + *((byte*~) main::$4) ← (number~) main::$5 + (byte) main::i#1 ← (byte) main::i#2 + rangenext(0,3) + (bool~) main::$6 ← (byte) main::i#1 != rangelast(0,3) + if((bool~) main::$6) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 + (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 + (byte) main::i1#0 ← (byte) 0 + to:main::@3 +main::@3: scope:[main] from main::@2 main::@3 + (byte) main::i1#2 ← phi( main::@2/(byte) main::i1#0 main::@3/(byte) main::i1#1 ) + (byte~) main::$15 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT + (struct Point*~) main::$7 ← (struct Point[4]) points#0 + (byte~) main::$15 + (struct Point*) main::point_i1#0 ← (struct Point*~) main::$7 + (byte*~) main::$8 ← ((byte*)) (struct Point*) main::point_i1#0 + (byte*~) main::$9 ← (byte*~) main::$8 + (byte) OFFS_X#0 + *((byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$9) + (byte*~) main::$10 ← (byte*) main::SCREEN#0 + (number) $28 + (byte*~) main::$11 ← ((byte*)) (struct Point*) main::point_i1#0 + (byte*~) main::$12 ← (byte*~) main::$11 + (byte) OFFS_Y#0 + *((byte*~) main::$10 + (byte) main::i1#2) ← *((byte*~) main::$12) + (byte) main::i1#1 ← (byte) main::i1#2 + rangenext(0,3) + (bool~) main::$13 ← (byte) main::i1#1 != rangelast(0,3) + if((bool~) main::$13) goto main::@3 + to:main::@return +main::@return: scope:[main] from main::@3 + 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 +(byte) OFFS_X +(byte) OFFS_X#0 +(byte) OFFS_Y +(byte) OFFS_Y#0 +(byte) Point::x +(byte) Point::y +(const byte) SIZEOF_STRUCT_POINT = (byte) 2 +(void()) main() +(struct Point*~) main::$0 +(byte*~) main::$1 +(byte*~) main::$10 +(byte*~) main::$11 +(byte*~) main::$12 +(bool~) main::$13 +(byte~) main::$14 +(byte~) main::$15 +(byte*~) main::$2 +(byte*~) main::$3 +(byte*~) main::$4 +(number~) main::$5 +(bool~) main::$6 +(struct Point*~) main::$7 +(byte*~) main::$8 +(byte*~) main::$9 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(byte) main::i1 +(byte) main::i1#0 +(byte) main::i1#1 +(byte) main::i1#2 +(struct Point*) main::point_i +(struct Point*) main::point_i#0 +(struct Point*) main::point_i1 +(struct Point*) main::point_i1#0 +(struct Point[4]) points +(struct Point[4]) points#0 + +Adding number conversion cast (unumber) 0 in (byte) OFFS_X#0 ← (number) 0 +Adding number conversion cast (unumber) 1 in (byte) OFFS_Y#0 ← (number) 1 +Adding number conversion cast (unumber) 4 in (number~) main::$5 ← (byte) main::i#2 + (number) 4 +Adding number conversion cast (unumber) main::$5 in (number~) main::$5 ← (byte) main::i#2 + (unumber)(number) 4 +Adding number conversion cast (unumber) $28 in (byte*~) main::$10 ← (byte*) main::SCREEN#0 + (number) $28 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte) OFFS_X#0 ← (unumber)(number) 0 +Inlining cast (byte) OFFS_Y#0 ← (unumber)(number) 1 +Inlining cast (byte*~) main::$1 ← (byte*)(struct Point*) main::point_i#0 +Inlining cast (byte*~) main::$3 ← (byte*)(struct Point*) main::point_i#0 +Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 +Inlining cast (byte*~) main::$8 ← (byte*)(struct Point*) main::point_i1#0 +Inlining cast (byte*~) main::$11 ← (byte*)(struct Point*) main::point_i1#0 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 +Simplifying constant integer cast 4 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast $28 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 4 +Finalized unsigned number type (byte) $28 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inferred type updated to byte in (unumber~) main::$5 ← (byte) main::i#2 + (byte) 4 +Alias (struct Point*) main::point_i#0 = (struct Point*~) main::$0 +Alias (struct Point*) main::point_i1#0 = (struct Point*~) main::$7 +Successful SSA optimization Pass2AliasElimination +Simple Condition (bool~) main::$6 [17] if((byte) main::i#1!=rangelast(0,3)) goto main::@1 +Simple Condition (bool~) main::$13 [33] if((byte) main::i1#1!=rangelast(0,3)) goto main::@3 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant right-side identified [0] (struct Point[4]) points#0 ← { fill( 4, 0) } +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const struct Point[4]) points#0 = { fill( 4, 0) } +Constant (const byte) OFFS_X#0 = 0 +Constant (const byte) OFFS_Y#0 = 1 +Constant (const byte) main::i#0 = 0 +Constant (const byte*) main::SCREEN#0 = (byte*) 1024 +Constant (const byte) main::i1#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Resolved ranged next value [15] main::i#1 ← ++ main::i#2 to ++ +Resolved ranged comparison value [17] if(main::i#1!=rangelast(0,3)) goto main::@1 to (number) 4 +Resolved ranged next value [31] main::i1#1 ← ++ main::i1#2 to ++ +Resolved ranged comparison value [33] if(main::i1#1!=rangelast(0,3)) goto main::@3 to (number) 4 +Converting *(pointer+n) to pointer[n] [10] *((byte*~) main::$2) ← (byte) main::i#2 -- *(main::$1 + OFFS_X#0) +Converting *(pointer+n) to pointer[n] [14] *((byte*~) main::$4) ← (byte~) main::$5 -- *(main::$3 + OFFS_Y#0) +Converting *(pointer+n) to pointer[n] [26] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$9) -- *(main::$8 + OFFS_X#0) +Converting *(pointer+n) to pointer[n] [30] *((byte*~) main::$10 + (byte) main::i1#2) ← *((byte*~) main::$12) -- *(main::$11 + OFFS_Y#0) +Successful SSA optimization Pass2InlineDerefIdx +Simplifying expression containing zero main::$1 in [9] (byte*~) main::$2 ← (byte*~) main::$1 + (const byte) OFFS_X#0 +Simplifying expression containing zero main::$1 in [10] *((byte*~) main::$1 + (const byte) OFFS_X#0) ← (byte) main::i#2 +Simplifying expression containing zero main::$8 in [25] (byte*~) main::$9 ← (byte*~) main::$8 + (const byte) OFFS_X#0 +Simplifying expression containing zero main::$8 in [26] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$8 + (const byte) OFFS_X#0) +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused variable (byte*~) main::$2 and assignment [4] (byte*~) main::$2 ← (byte*~) main::$1 +Eliminating unused variable (byte*~) main::$4 and assignment [7] (byte*~) main::$4 ← (byte*~) main::$3 + (const byte) OFFS_Y#0 +Eliminating unused variable (byte*~) main::$9 and assignment [16] (byte*~) main::$9 ← (byte*~) main::$8 +Eliminating unused variable (byte*~) main::$12 and assignment [20] (byte*~) main::$12 ← (byte*~) main::$11 + (const byte) OFFS_Y#0 +Eliminating unused constant (const byte) OFFS_X#0 +Successful SSA optimization PassNEliminateUnusedVars +Adding number conversion cast (unumber) 4 in if((byte) main::i#1!=(number) 4) goto main::@1 +Adding number conversion cast (unumber) 4 in if((byte) main::i1#1!=(number) 4) goto main::@3 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant integer cast 4 +Simplifying constant integer cast 4 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 4 +Finalized unsigned number type (byte) 4 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Constant right-side identified [15] (byte*~) main::$10 ← (const byte*) main::SCREEN#0 + (byte) $28 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::$10 = main::SCREEN#0+$28 +Successful SSA optimization Pass2ConstantIdentification +Converting *(pointer+n) to pointer[n] [4] *((byte*~) main::$1) ← (byte) main::i#2 -- *((byte*)points#0 + main::$14) +Converting *(pointer+n) to pointer[n] [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$8) -- *((byte*)points#0 + main::$15) +Successful SSA optimization Pass2InlineDerefIdx +Eliminating unused variable (byte*~) main::$1 and assignment [3] (byte*~) main::$1 ← (byte*)(struct Point*) main::point_i#0 +Eliminating unused variable (byte*~) main::$8 and assignment [13] (byte*~) main::$8 ← (byte*)(struct Point*) main::point_i1#0 +Successful SSA optimization PassNEliminateUnusedVars +Constant value identified (byte*)points#0 in [3] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 +Constant value identified (byte*)points#0 in [12] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) +Successful SSA optimization Pass2ConstantValues +Inlining Noop Cast [4] (byte*~) main::$3 ← (byte*)(struct Point*) main::point_i#0 keeping main::point_i#0 +Inlining Noop Cast [13] (byte*~) main::$11 ← (byte*)(struct Point*) main::point_i1#0 keeping main::point_i1#0 +Successful SSA optimization Pass2NopCastInlining +Rewriting multiplication to use shift [1] (byte~) main::$14 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT +Rewriting multiplication to use shift [10] (byte~) main::$15 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization Pass2MultiplyToShiftRewriting +Inlining constant with var siblings (const byte) main::i#0 +Inlining constant with var siblings (const byte) main::i1#0 +Constant inlined main::i#0 = (byte) 0 +Constant inlined main::i1#0 = (byte) 0 +Constant inlined main::$10 = (const byte*) main::SCREEN#0+(byte) $28 +Successful SSA optimization Pass2ConstantInlining +Eliminating unused constant (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization PassNEliminateUnusedVars +Added new block during phi lifting main::@5(between main::@1 and main::@1) +Added new block during phi lifting main::@6(between main::@3 and main::@3) +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 +Adding NOP phi() at start of main::@2 +CALL GRAPH +Calls in [] to main:2 + +Created 2 initial phi equivalence classes +Coalesced [23] main::i1#3 ← main::i1#1 +Coalesced [24] main::i#3 ← main::i#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) @2 +Culled Empty Block (label) main::@2 +Culled Empty Block (label) main::@6 +Culled Empty Block (label) main::@5 +Renumbering block main::@3 to main::@2 +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() + 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] 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 ) + [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 + [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 + [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 + [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 + [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 + [11] (byte) main::i#1 ← ++ (byte) main::i#2 + [12] if((byte) main::i#1!=(byte) 4) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [13] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) + [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 + [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 + [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) + [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) + [18] (byte) main::i1#1 ← ++ (byte) main::i1#2 + [19] if((byte) main::i1#1!=(byte) 4) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@2 + [20] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte) OFFS_X +(byte) OFFS_Y +(byte) Point::x +(byte) Point::y +(void()) main() +(byte~) main::$14 16.5 +(byte~) main::$15 16.5 +(byte~) main::$5 22.0 +(byte*) main::SCREEN +(byte) main::i +(byte) main::i#1 16.5 +(byte) main::i#2 9.166666666666666 +(byte) main::i1 +(byte) main::i1#1 16.5 +(byte) main::i1#2 11.0 +(struct Point*) main::point_i +(struct Point*) main::point_i#0 3.6666666666666665 +(struct Point*) main::point_i1 +(struct Point*) main::point_i1#0 5.5 +(struct Point[4]) points + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +[ main::i1#2 main::i1#1 ] +Added variable main::$14 to zero page equivalence class [ main::$14 ] +Added variable main::point_i#0 to zero page equivalence class [ main::point_i#0 ] +Added variable main::$5 to zero page equivalence class [ main::$5 ] +Added variable main::$15 to zero page equivalence class [ main::$15 ] +Added variable main::point_i1#0 to zero page equivalence class [ main::point_i1#0 ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ main::i1#2 main::i1#1 ] +[ main::$14 ] +[ main::point_i#0 ] +[ main::$5 ] +[ main::$15 ] +[ main::point_i1#0 ] +Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Allocated zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Allocated zp ZP_BYTE:4 [ main::$14 ] +Allocated zp ZP_WORD:5 [ main::point_i#0 ] +Allocated zp ZP_BYTE:7 [ main::$5 ] +Allocated zp ZP_BYTE:8 [ main::$15 ] +Allocated zp ZP_WORD:9 [ main::point_i1#0 ] + +INITIAL ASM +//SEG0 File Comments +// Minimal struct - array of struct - far pointer math indexing +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFS_Y = 1 +//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 +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + .label _5 = 7 + .label _14 = 4 + .label _15 = 8 + .label point_i = 5 + .label i = 2 + .label point_i1 = 9 + .label i1 = 3 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta i + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda i + asl + sta _14 + //SEG17 [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 -- pssz1=pssc1_plus_vbuz2 + lda _14 + clc + adc #points + adc #0 + sta point_i+1 + //SEG18 [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 -- pbuc1_derefidx_vbuz1=vbuz2 + lda i + ldy _14 + sta points,y + //SEG19 [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 -- vbuz1=vbuz2_plus_vbuc1 + lax i + axs #-[4] + stx _5 + //SEG20 [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 -- pbuz1_derefidx_vbuc1=vbuz2 + // points[i].x = i; + lda _5 + ldy #OFFS_Y + sta (point_i),y + //SEG21 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc i + //SEG22 [12] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 + lda #4 + cmp i + bne b1_from_b1 + //SEG23 [13] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG24 [13] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 + lda #0 + sta i1 + jmp b2 + //SEG25 [13] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG26 [13] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy + jmp b2 + //SEG27 main::@2 + b2: + //SEG28 [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda i1 + asl + sta _15 + //SEG29 [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 -- pssz1=pssc1_plus_vbuz2 + lda _15 + clc + adc #points + adc #0 + sta point_i1+1 + //SEG30 [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2 + ldy _15 + lda points,y + ldy i1 + sta SCREEN,y + //SEG31 [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuc2 + // SCREEN[i] = points[i].x; + ldx i1 + ldy #OFFS_Y + lda (point_i1),y + sta SCREEN+$28,x + //SEG32 [18] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1 + inc i1 + //SEG33 [19] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuz1_neq_vbuc1_then_la1 + lda #4 + cmp i1 + bne b2_from_b2 + jmp breturn + //SEG34 main::@return + breturn: + //SEG35 [20] return + rts +} + points: .fill 2*4, 0 + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$14 ] ( main:2 [ main::i#2 main::$14 ] ) 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 [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 [ main::i#2 main::$14 main::point_i#0 ] ( main:2 [ main::i#2 main::$14 main::point_i#0 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::$14 ] +Statement [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 [ main::i#2 main::point_i#0 ] ( main:2 [ main::i#2 main::point_i#0 ] ) always clobbers reg byte a +Statement [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 [ main::i#2 main::point_i#0 main::$5 ] ( main:2 [ main::i#2 main::point_i#0 main::$5 ] ) always clobbers reg byte a +Statement [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte y +Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Statement [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$15 ] ( main:2 [ main::i1#2 main::$15 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Statement [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 [ main::i1#2 main::$15 main::point_i1#0 ] ( main:2 [ main::i1#2 main::$15 main::point_i1#0 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:8 [ main::$15 ] +Statement [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) [ main::i1#2 main::point_i1#0 ] ( main:2 [ main::i1#2 main::point_i1#0 ] ) always clobbers reg byte a +Statement [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a reg byte y +Removing always clobbered register reg byte y as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Statement [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$14 ] ( main:2 [ main::i#2 main::$14 ] ) always clobbers reg byte a +Statement [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 [ main::i#2 main::$14 main::point_i#0 ] ( main:2 [ main::i#2 main::$14 main::point_i#0 ] ) always clobbers reg byte a +Statement [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 [ main::i#2 main::point_i#0 ] ( main:2 [ main::i#2 main::point_i#0 ] ) always clobbers reg byte a +Statement [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 [ main::i#2 main::point_i#0 main::$5 ] ( main:2 [ main::i#2 main::point_i#0 main::$5 ] ) always clobbers reg byte a +Statement [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte y +Statement [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$15 ] ( main:2 [ main::i1#2 main::$15 ] ) always clobbers reg byte a +Statement [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 [ main::i1#2 main::$15 main::point_i1#0 ] ( main:2 [ main::i1#2 main::$15 main::point_i1#0 ] ) always clobbers reg byte a +Statement [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) [ main::i1#2 main::point_i1#0 ] ( main:2 [ main::i1#2 main::point_i1#0 ] ) always clobbers reg byte a +Statement [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a reg byte y +Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , +Potential registers zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] : zp ZP_BYTE:3 , reg byte x , +Potential registers zp ZP_BYTE:4 [ main::$14 ] : zp ZP_BYTE:4 , reg byte x , reg byte y , +Potential registers zp ZP_WORD:5 [ main::point_i#0 ] : zp ZP_WORD:5 , +Potential registers zp ZP_BYTE:7 [ main::$5 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:8 [ main::$15 ] : zp ZP_BYTE:8 , reg byte x , reg byte y , +Potential registers zp ZP_WORD:9 [ main::point_i1#0 ] : zp ZP_WORD:9 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 27.5: zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] 25.67: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:7 [ main::$5 ] 16.5: zp ZP_BYTE:4 [ main::$14 ] 16.5: zp ZP_BYTE:8 [ main::$15 ] 5.5: zp ZP_WORD:9 [ main::point_i1#0 ] 3.67: zp ZP_WORD:5 [ main::point_i#0 ] +Uplift Scope [Point] +Uplift Scope [] + +Uplifting [main] best 1258 combination reg byte x [ main::i1#2 main::i1#1 ] reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$5 ] reg byte y [ main::$14 ] zp ZP_BYTE:8 [ main::$15 ] zp ZP_WORD:9 [ main::point_i1#0 ] zp ZP_WORD:5 [ main::point_i#0 ] +Limited combination testing to 100 combinations of 144 possible. +Uplifting [Point] best 1258 combination +Uplifting [] best 1258 combination +Attempting to uplift remaining variables inzp ZP_BYTE:8 [ main::$15 ] +Uplifting [main] best 1208 combination reg byte y [ main::$15 ] +Allocated (was zp ZP_WORD:5) zp ZP_WORD:2 [ main::point_i#0 ] +Allocated (was zp ZP_WORD:9) zp ZP_WORD:4 [ main::point_i1#0 ] + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Minimal struct - array of struct - far pointer math indexing +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFS_Y = 1 +//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 +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + .label point_i = 2 + .label point_i1 = 4 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuxx_rol_1 + txa + asl + tay + //SEG17 [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 -- pssz1=pssc1_plus_vbuyy + tya + clc + adc #points + adc #0 + sta point_i+1 + //SEG18 [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 -- pbuc1_derefidx_vbuyy=vbuxx + txa + sta points,y + //SEG19 [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 -- vbuaa=vbuxx_plus_vbuc1 + txa + clc + adc #4 + //SEG20 [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 -- pbuz1_derefidx_vbuc1=vbuaa + // points[i].x = i; + ldy #OFFS_Y + sta (point_i),y + //SEG21 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + //SEG22 [12] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #4 + bne b1_from_b1 + //SEG23 [13] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG24 [13] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1 + ldx #0 + jmp b2 + //SEG25 [13] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG26 [13] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy + jmp b2 + //SEG27 main::@2 + b2: + //SEG28 [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 -- vbuyy=vbuxx_rol_1 + txa + asl + tay + //SEG29 [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 -- pssz1=pssc1_plus_vbuyy + tya + clc + adc #points + adc #0 + sta point_i1+1 + //SEG30 [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy + lda points,y + sta SCREEN,x + //SEG31 [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2 + // SCREEN[i] = points[i].x; + ldy #OFFS_Y + lda (point_i1),y + sta SCREEN+$28,x + //SEG32 [18] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuxx=_inc_vbuxx + inx + //SEG33 [19] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuxx_neq_vbuc1_then_la1 + cpx #4 + bne b2_from_b2 + jmp breturn + //SEG34 main::@return + breturn: + //SEG35 [20] return + rts +} + points: .fill 2*4, 0 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing label b1_from_b1 with b1 +Replacing label b2_from_b2 with b2 +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_b1: +Removing instruction b2_from_b2: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b2_from_b1: +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 +Removing instruction jmp b2 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(byte) OFFS_X +(byte) OFFS_Y +(const byte) OFFS_Y#0 OFFS_Y = (byte) 1 +(byte) Point::x +(byte) Point::y +(void()) main() +(byte~) main::$14 reg byte y 16.5 +(byte~) main::$15 reg byte y 16.5 +(byte~) main::$5 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 9.166666666666666 +(byte) main::i1 +(byte) main::i1#1 reg byte x 16.5 +(byte) main::i1#2 reg byte x 11.0 +(struct Point*) main::point_i +(struct Point*) main::point_i#0 point_i zp ZP_WORD:2 3.6666666666666665 +(struct Point*) main::point_i1 +(struct Point*) main::point_i1#0 point_i1 zp ZP_WORD:4 5.5 +(struct Point[4]) points +(const struct Point[4]) points#0 points = { fill( 4, 0) } + +reg byte x [ main::i#2 main::i#1 ] +reg byte x [ main::i1#2 main::i1#1 ] +reg byte y [ main::$14 ] +zp ZP_WORD:2 [ main::point_i#0 ] +reg byte a [ main::$5 ] +reg byte y [ main::$15 ] +zp ZP_WORD:4 [ main::point_i1#0 ] + + +FINAL ASSEMBLER +Score: 1046 + +//SEG0 File Comments +// Minimal struct - array of struct - far pointer math indexing +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFS_Y = 1 +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG9 @end +//SEG10 main +main: { + .label SCREEN = $400 + .label point_i = 2 + .label point_i1 = 4 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuxx_rol_1 + txa + asl + tay + //SEG17 [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 -- pssz1=pssc1_plus_vbuyy + tya + clc + adc #points + adc #0 + sta point_i+1 + //SEG18 [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 -- pbuc1_derefidx_vbuyy=vbuxx + txa + sta points,y + //SEG19 [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 -- vbuaa=vbuxx_plus_vbuc1 + txa + clc + adc #4 + //SEG20 [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 -- pbuz1_derefidx_vbuc1=vbuaa + // points[i].x = i; + ldy #OFFS_Y + sta (point_i),y + //SEG21 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + //SEG22 [12] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #4 + bne b1 + //SEG23 [13] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG24 [13] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1 + ldx #0 + //SEG25 [13] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + //SEG26 [13] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy + //SEG27 main::@2 + b2: + //SEG28 [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 -- vbuyy=vbuxx_rol_1 + txa + asl + tay + //SEG29 [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 -- pssz1=pssc1_plus_vbuyy + tya + clc + adc #points + adc #0 + sta point_i1+1 + //SEG30 [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy + lda points,y + sta SCREEN,x + //SEG31 [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2 + // SCREEN[i] = points[i].x; + ldy #OFFS_Y + lda (point_i1),y + sta SCREEN+$28,x + //SEG32 [18] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuxx=_inc_vbuxx + inx + //SEG33 [19] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuxx_neq_vbuc1_then_la1 + cpx #4 + bne b2 + //SEG34 main::@return + //SEG35 [20] return + rts +} + points: .fill 2*4, 0 + diff --git a/src/test/ref/struct-ptr-2.sym b/src/test/ref/struct-ptr-2.sym new file mode 100644 index 000000000..1daabbadc --- /dev/null +++ b/src/test/ref/struct-ptr-2.sym @@ -0,0 +1 @@ +program \ No newline at end of file