diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index e30156bdf..1cf34db63 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -165,6 +165,8 @@ public class Compiler { new PassNTypeInference(program).execute(); new PassNTypeIdSimplification(program).execute(); + new Pass1UnwindStructValues(program).execute(); + if(getLog().isVerbosePass1CreateSsa()) { getLog().append("SYMBOLS"); getLog().append(program.getScope().toString(program, null)); diff --git a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeStruct.java b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeStruct.java index bc6cb3082..3d50066f1 100644 --- a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeStruct.java +++ b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeStruct.java @@ -1,5 +1,6 @@ package dk.camelot64.kickc.model.types; +import dk.camelot64.kickc.model.symbols.ProgramScope; import dk.camelot64.kickc.model.symbols.StructDefinition; import dk.camelot64.kickc.model.symbols.Variable; @@ -32,6 +33,10 @@ public class SymbolTypeStruct implements SymbolType { return name; } + public StructDefinition getStructDefinition(ProgramScope programScope) { + return programScope.getStructDefinition(name); + } + @Override public int getSizeBytes() { return sizeBytes; diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java index ef04864be..65a7c5e25 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java @@ -125,8 +125,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor { try { ConstantString.Encoding encoding = ConstantString.Encoding.valueOf(ctx.NAME().getText().toUpperCase()); this.currentEncoding = encoding; - } catch( IllegalArgumentException e) { - throw new CompileError("Unknown string encoding "+ctx.NAME().getText(), new StatementSource(ctx)); + } catch(IllegalArgumentException e) { + throw new CompileError("Unknown string encoding " + ctx.NAME().getText(), new StatementSource(ctx)); } return null; } @@ -518,9 +518,9 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor { // Add comments to constant lValue.setComments(ensureUnusedComments(comments)); } - if(type instanceof SymbolTypeStruct) { - lValue.setDeclaredVolatile(true); - } + //if(type instanceof SymbolTypeStruct) { + // lValue.setDeclaredVolatile(true); + //} KickCParser.ExprContext initializer = ctx.expr(); if(declVarStructMember) { if(initializer != null) { @@ -530,40 +530,53 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor { if(initializer != null) { addInitialAssignment(initializer, lValue, comments); } else { - if(type instanceof SymbolTypeIntegerFixed) { - // Add an zero value initializer - ConstantInteger zero = new ConstantInteger(0L, type); - Statement stmt = new StatementAssignment(lValue.getRef(), zero, new StatementSource(ctx), ensureUnusedComments(comments)); - sequence.addStatement(stmt); - } else if(type instanceof SymbolTypeArray) { - // Add an zero-array initializer - SymbolTypeArray typeArray = (SymbolTypeArray) type; - RValue size = typeArray.getSize(); - if(size == null) { - throw new CompileError("Error! Array has no declared size. " + lValue.toString(program), new StatementSource(ctx)); - } - Statement stmt = new StatementAssignment(lValue.getRef(), new ArrayFilled(typeArray.getElementType(), size), new StatementSource(ctx), ensureUnusedComments(comments)); - sequence.addStatement(stmt); - } else if(type instanceof SymbolTypePointer) { - // Add an zero value initializer - SymbolTypePointer typePointer = (SymbolTypePointer) type; - ConstantValue zero = new ConstantPointer(0L, typePointer.getElementType()); - Statement stmt = new StatementAssignment(lValue.getRef(), zero, new StatementSource(ctx), ensureUnusedComments(comments)); - sequence.addStatement(stmt); - } else if(type instanceof SymbolTypeStruct) { - // Add an zero-struct initializer - SymbolTypeStruct typeStruct = (SymbolTypeStruct) type; - Statement stmt = new StatementAssignment(lValue.getRef(), new StructZero(typeStruct), new StatementSource(ctx), ensureUnusedComments(comments)); - sequence.addStatement(stmt); - } else { - throw new CompileError("Default initializer not implemented for type " + type.getTypeName(), new StatementSource(ctx)); - } + Statement initStmt; + StatementSource statementSource = new StatementSource(ctx); + initStmt = createDefaultInitializationStatement(lValue.getRef(), type, statementSource, ensureUnusedComments(comments)); + sequence.addStatement(initStmt); } } return null; } + /** + * Create a statement that initializes a variable with the default (zero) value. The statement has to be added to the program by the caller. + * @param lValue The variable to initialize + * @param type The type of the variable + * @param statementSource The source line + * @param comments Any comments to add to the output + * @return The new statement + */ + public static Statement createDefaultInitializationStatement(VariableRef varRef, SymbolType type, StatementSource statementSource, List comments) { + Statement initStmt; + if(type instanceof SymbolTypeIntegerFixed) { + // Add an zero value initializer + ConstantInteger zero = new ConstantInteger(0L, type); + initStmt = new StatementAssignment(varRef, zero, statementSource, comments); + } else if(type instanceof SymbolTypeArray) { + // Add an zero-array initializer + SymbolTypeArray typeArray = (SymbolTypeArray) type; + RValue size = typeArray.getSize(); + if(size == null) { + throw new CompileError("Error! Array has no declared size. " + varRef.toString(), statementSource); + } + initStmt = new StatementAssignment(varRef, new ArrayFilled(typeArray.getElementType(), size), statementSource, comments); + } else if(type instanceof SymbolTypePointer) { + // Add an zero value initializer + SymbolTypePointer typePointer = (SymbolTypePointer) type; + ConstantValue zero = new ConstantPointer(0L, typePointer.getElementType()); + initStmt = new StatementAssignment(varRef, zero, statementSource, comments); + } else if(type instanceof SymbolTypeStruct) { + // Add an zero-struct initializer + SymbolTypeStruct typeStruct = (SymbolTypeStruct) type; + initStmt = new StatementAssignment(varRef, new StructZero(typeStruct), statementSource, comments); + } else { + throw new CompileError("Default initializer not implemented for type " + type.getTypeName(), statementSource); + } + return initStmt; + } + /** * Add declared directives to an lValue (typically a variable). * diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java b/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java new file mode 100644 index 000000000..c2c9c139b --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java @@ -0,0 +1,138 @@ +package dk.camelot64.kickc.passes; + +import dk.camelot64.kickc.model.Comment; +import dk.camelot64.kickc.model.ControlFlowBlock; +import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.iterator.ProgramValueIterator; +import dk.camelot64.kickc.model.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.types.SymbolTypeStruct; +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; + +/** Convert all struct values that are not used as pointers (address-of used or declared volatile) */ +public class Pass1UnwindStructValues extends Pass1Base { + + public Pass1UnwindStructValues(Program program) { + super(program); + } + + @Override + public boolean step() { + boolean modified = false; + + // Maps struct variable to map from member name to the variable + Map> structMemberVariableMap = new LinkedHashMap<>(); + + // Iterate through all scopes generating member-variables for each struct + for(Variable variable : getScope().getAllVariables(true)) { + if(variable.getType() instanceof SymbolTypeStruct) { + if(!variable.isDeclaredVolatile() && !Pass2ConstantIdentification.isAddressOfUsed(variable.getRef(), getProgram())) { + // A non-volatile struct variable + Scope scope = variable.getScope(); + StructDefinition structDefinition = ((SymbolTypeStruct) variable.getType()).getStructDefinition(getProgram().getScope()); + LinkedHashMap memberVariables = new LinkedHashMap<>(); + for(Variable member : structDefinition.getAllVariables(false)) { + Variable memberVariable; + if(variable.getRef().isIntermediate()) { + memberVariable = scope.add(new VariableIntermediate(scope.allocateIntermediateVariableName() + "_" + member.getLocalName(), scope, member.getType())); + } else { + memberVariable = scope.addVariable(variable.getLocalName() + "_" + member.getLocalName(), member.getType()); + } + memberVariables.put(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())); + } + } + } + + // Unwind all references to full structs + for(ControlFlowBlock block : getGraph().getAllBlocks()) { + ListIterator stmtIt = block.getStatements().listIterator(); + while(stmtIt.hasNext()) { + Statement statement = stmtIt.next(); + if(statement instanceof StatementAssignment) { + StatementAssignment assignment = (StatementAssignment) statement; + if(assignment.getlValue() instanceof VariableRef) { + Variable assignedVar = getScope().getVariable((VariableRef) assignment.getlValue()); + if(assignedVar.getType() instanceof SymbolTypeStruct) { + // 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) { + stmtIt.previous(); + for(String memberName : memberVariables.keySet()) { + VariableRef memberVarRef = memberVariables.get(memberName); + Variable memberVar = getScope().getVariable(memberVarRef); + Statement initStmt = Pass0GenerateStatementSequence.createDefaultInitializationStatement(memberVarRef, memberVar.getType(), statement.getSource(), Comment.NO_COMMENTS); + stmtIt.add(initStmt); + getLog().append("Adding struct value member variable default initializer " + initStmt.toString(getProgram(), false)); + } + stmtIt.next(); + stmtIt.remove(); + } + } else if(assignment.getOperator() == null && assignment.getrValue2() instanceof VariableRef) { + 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) { + stmtIt.previous(); + for(String memberName : assignedMemberVariables.keySet()) { + VariableRef assignedMemberVarRef = assignedMemberVariables.get(memberName); + VariableRef sourceMemberVarRef = sourceMemberVariables.get(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)); + } + } + } + } + } + } + } + + // Change all usages of members in 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); + } + } + } + }); + + + return modified; +} + +} diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index d2d5f5031..3732ca005 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -36,6 +36,36 @@ public class TestPrograms { } + @Test + public void testStruct5() throws IOException, URISyntaxException { + compileAndCompare("struct-5", log()); + } + + @Test + public void testStruct4() throws IOException, URISyntaxException { + compileAndCompare("struct-4", log()); + } + + @Test + public void testStruct3() throws IOException, URISyntaxException { + compileAndCompare("struct-3", log()); + } + + @Test + public void testStruct2() throws IOException, URISyntaxException { + compileAndCompare("struct-2", log()); + } + + @Test + public void testStruct1() throws IOException, URISyntaxException { + compileAndCompare("struct-1", log()); + } + + @Test + public void testStruct0() throws IOException, URISyntaxException { + compileAndCompare("struct-0", log()); + } + @Test public void testSequenceLocality1() throws IOException, URISyntaxException { compileAndCompare("sequence-locality-1"); @@ -115,36 +145,6 @@ public class TestPrograms { compileAndCompare("signed-word-minus-byte-2"); } - @Test - public void testStruct5() throws IOException, URISyntaxException { - compileAndCompare("struct-5", log().verboseParse().verboseCreateSsa().verboseStatementSequence()); - } - - @Test - public void testStruct4() throws IOException, URISyntaxException { - compileAndCompare("struct-4", log().verboseParse().verboseCreateSsa().verboseStatementSequence()); - } - - @Test - public void testStruct3() throws IOException, URISyntaxException { - compileAndCompare("struct-3"); - } - - @Test - public void testStruct2() throws IOException, URISyntaxException { - compileAndCompare("struct-2"); - } - - @Test - public void testStruct1() throws IOException, URISyntaxException { - compileAndCompare("struct-1"); - } - - @Test - public void testStruct0() throws IOException, URISyntaxException { - compileAndCompare("struct-0"); - } - @Test public void testForTwoVars() throws IOException, URISyntaxException { compileAndCompare("for-two-vars"); diff --git a/src/test/ref/struct-0.asm b/src/test/ref/struct-0.asm index 46b08a2aa..10a801c95 100644 --- a/src/test/ref/struct-0.asm +++ b/src/test/ref/struct-0.asm @@ -1,23 +1,14 @@ // Minimal struct - declaration, instantiation and usage .pc = $801 "Basic" -:BasicUpstart(bbegin) +:BasicUpstart(main) .pc = $80d "Program" - .label point = 2 -bbegin: - lda #0 - sta point - sta point+1 - jsr main - rts + .const point_x = 2 + .const point_y = 3 main: { .label SCREEN = $400 - lda #2 - sta point+0 - lda #3 - sta point+1 - lda point+0 + lda #point_x sta SCREEN - lda point+1 + lda #point_y sta SCREEN+1 rts } diff --git a/src/test/ref/struct-0.cfg b/src/test/ref/struct-0.cfg index 7ada6cec1..04634cd53 100644 --- a/src/test/ref/struct-0.cfg +++ b/src/test/ref/struct-0.cfg @@ -1,5 +1,5 @@ @begin: scope:[] from - [0] (struct Point) point#0 ← {} + [0] phi() to:@1 @1: scope:[] from @begin [1] phi() @@ -8,11 +8,9 @@ @end: scope:[] from @1 [3] phi() main: scope:[main] from @1 - [4] (struct Point) point#0.x ← (byte) 2 - [5] (struct Point) point#0.y ← (byte) 3 - [6] *((const byte*) main::SCREEN#0) ← (struct Point) point#0.x - [7] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point#0.y + [4] *((const byte*) main::SCREEN#0) ← (const byte) point_x#1 + [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point_y#1 to:main::@return main::@return: scope:[main] from main - [8] return + [6] return to:@return diff --git a/src/test/ref/struct-0.log b/src/test/ref/struct-0.log index 9a5a302f1..58153446a 100644 --- a/src/test/ref/struct-0.log +++ b/src/test/ref/struct-0.log @@ -1,25 +1,43 @@ +Created struct value member variable (byte) point_x +Created struct value member variable (byte) point_y +Converted struct value to member variables (struct Point) point +Adding struct value member variable default initializer (byte) point_x ← (byte) 0 +Adding struct value member variable default initializer (byte) point_y ← (byte) 0 +Replacing struct member reference (struct Point) point.x with member variable reference (byte) point_x +Replacing struct member reference (struct Point) point.y with member variable reference (byte) point_y +Replacing struct member reference (struct Point) point.x with member variable reference (byte) point_x +Replacing struct member reference (struct Point) point.y with member variable reference (byte) point_y Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 CONTROL FLOW GRAPH SSA @begin: scope:[] from - (struct Point) point#0 ← {} + (byte) point_x#0 ← (byte) 0 + (byte) point_y#0 ← (byte) 0 to:@1 main: scope:[main] from @1 - (struct Point) point#1 ← phi( @1/(struct Point) point#2 ) - (struct Point) point#1.x ← (number) 2 - (struct Point) point#1.y ← (number) 3 + (byte) point_x#1 ← (number) 2 + (byte) point_y#1 ← (number) 3 (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 - *((byte*) main::SCREEN#0 + (number) 0) ← (struct Point) point#1.x - *((byte*) main::SCREEN#0 + (number) 1) ← (struct Point) point#1.y + *((byte*) main::SCREEN#0 + (number) 0) ← (byte) point_x#1 + *((byte*) main::SCREEN#0 + (number) 1) ← (byte) point_y#1 to:main::@return main::@return: scope:[main] from main + (byte) point_y#4 ← phi( main/(byte) point_y#1 ) + (byte) point_x#4 ← phi( main/(byte) point_x#1 ) + (byte) point_x#2 ← (byte) point_x#4 + (byte) point_y#2 ← (byte) point_y#4 return to:@return @1: scope:[] from @begin - (struct Point) point#2 ← phi( @begin/(struct Point) point#0 ) + (byte) point_y#6 ← phi( @begin/(byte) point_y#0 ) + (byte) point_x#6 ← phi( @begin/(byte) point_x#0 ) call main to:@2 @2: scope:[] from @1 + (byte) point_y#5 ← phi( @1/(byte) point_y#2 ) + (byte) point_x#5 ← phi( @1/(byte) point_x#2 ) + (byte) point_x#3 ← (byte) point_x#5 + (byte) point_y#3 ← (byte) point_y#5 to:@end @end: scope:[] from @2 @@ -35,17 +53,30 @@ SYMBOL TABLE SSA (byte*) main::SCREEN (byte*) main::SCREEN#0 (struct Point) point -(struct Point) point#0 -(struct Point) point#1 -(struct Point) point#2 +(byte) point_x +(byte) point_x#0 +(byte) point_x#1 +(byte) point_x#2 +(byte) point_x#3 +(byte) point_x#4 +(byte) point_x#5 +(byte) point_x#6 +(byte) point_y +(byte) point_y#0 +(byte) point_y#1 +(byte) point_y#2 +(byte) point_y#3 +(byte) point_y#4 +(byte) point_y#5 +(byte) point_y#6 -Adding number conversion cast (unumber) 2 in (struct Point) point#1.x ← (number) 2 -Adding number conversion cast (unumber) 3 in (struct Point) point#1.y ← (number) 3 -Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← (struct Point) point#1.x -Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← (struct Point) point#1.y +Adding number conversion cast (unumber) 2 in (byte) point_x#1 ← (number) 2 +Adding number conversion cast (unumber) 3 in (byte) point_y#1 ← (number) 3 +Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← (byte) point_x#1 +Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← (byte) point_y#1 Successful SSA optimization PassNAddNumberTypeConversions -Inlining cast (struct Point) point#1.x ← (unumber)(number) 2 -Inlining cast (struct Point) point#1.y ← (unumber)(number) 3 +Inlining cast (byte) point_x#1 ← (unumber)(number) 2 +Inlining cast (byte) point_y#1 ← (unumber)(number) 3 Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 Successful SSA optimization Pass2InlineCast Simplifying constant integer cast 2 @@ -59,16 +90,30 @@ Finalized unsigned number type (byte) 3 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 1 Successful SSA optimization PassNFinalizeNumberTypeConversions -Alias (struct Point) point#0 = (struct Point) point#2 +Alias (byte) point_x#1 = (byte) point_x#4 (byte) point_x#2 +Alias (byte) point_y#1 = (byte) point_y#4 (byte) point_y#2 +Alias (byte) point_x#0 = (byte) point_x#6 +Alias (byte) point_y#0 = (byte) point_y#6 +Alias (byte) point_x#3 = (byte) point_x#5 +Alias (byte) point_y#3 = (byte) point_y#5 Successful SSA optimization Pass2AliasElimination -Identical Phi Values (struct Point) point#1 (struct Point) point#0 +Identical Phi Values (byte) point_x#3 (byte) point_x#1 +Identical Phi Values (byte) point_y#3 (byte) point_y#1 Successful SSA optimization Pass2IdenticalPhiElimination +Constant (const byte) point_x#0 = 0 +Constant (const byte) point_y#0 = 0 +Constant (const byte) point_x#1 = 2 +Constant (const byte) point_y#1 = 3 Constant (const byte*) main::SCREEN#0 = (byte*) 1024 Successful SSA optimization Pass2ConstantIdentification -Simplifying expression containing zero main::SCREEN#0 in [5] *((const byte*) main::SCREEN#0 + (byte) 0) ← (struct Point) point#0.x +Simplifying expression containing zero main::SCREEN#0 in [5] *((const byte*) main::SCREEN#0 + (byte) 0) ← (const byte) point_x#1 Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused constant (const byte) point_x#0 +Eliminating unused constant (const byte) point_y#0 +Successful SSA optimization PassNEliminateUnusedVars Consolidated array index constant in *(main::SCREEN#0+1) Successful SSA optimization Pass2ConstantAdditionElimination +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 @@ -78,12 +123,13 @@ Calls in [] to main:2 Created 0 initial phi equivalence classes Coalesced down to 0 phi equivalence classes Culled Empty Block (label) @2 +Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @end FINAL CONTROL FLOW GRAPH @begin: scope:[] from - [0] (struct Point) point#0 ← {} + [0] phi() to:@1 @1: scope:[] from @begin [1] phi() @@ -92,13 +138,11 @@ FINAL CONTROL FLOW GRAPH @end: scope:[] from @1 [3] phi() main: scope:[main] from @1 - [4] (struct Point) point#0.x ← (byte) 2 - [5] (struct Point) point#0.y ← (byte) 3 - [6] *((const byte*) main::SCREEN#0) ← (struct Point) point#0.x - [7] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point#0.y + [4] *((const byte*) main::SCREEN#0) ← (const byte) point_x#1 + [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point_y#1 to:main::@return main::@return: scope:[main] from main - [8] return + [6] return to:@return @@ -108,12 +152,11 @@ VARIABLE REGISTER WEIGHTS (void()) main() (byte*) main::SCREEN (struct Point) point -(struct Point) point#0 0.4 +(byte) point_x +(byte) point_y Initial phi equivalence classes Complete equivalence classes -[ point#0 ] -Allocated zp ZP_STRUCT:2 [ point#0 ] INITIAL ASM //SEG0 File Comments @@ -123,63 +166,50 @@ INITIAL ASM :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels - .label point = 2 + .const point_x = 2 + .const point_y = 3 //SEG3 @begin bbegin: -//SEG4 [0] (struct Point) point#0 ← {} -- vssz1=vssf2 - lda #0 - sta point - sta point+1 -//SEG5 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] b1_from_bbegin: jmp b1 -//SEG6 @1 +//SEG5 @1 b1: -//SEG7 [2] call main +//SEG6 [2] call main jsr main -//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG7 [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: jmp bend -//SEG9 @end +//SEG8 @end bend: -//SEG10 main +//SEG9 main main: { .label SCREEN = $400 - //SEG11 [4] (struct Point) point#0.x ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta point+0 - //SEG12 [5] (struct Point) point#0.y ← (byte) 3 -- vbuz1=vbuc1 - lda #3 - sta point+1 - //SEG13 [6] *((const byte*) main::SCREEN#0) ← (struct Point) point#0.x -- _deref_pbuc1=vbuz1 - lda point+0 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) point_x#1 -- _deref_pbuc1=vbuc2 + lda #point_x sta SCREEN - //SEG14 [7] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point#0.y -- _deref_pbuc1=vbuz1 - lda point+1 + //SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point_y#1 -- _deref_pbuc1=vbuc2 + lda #point_y sta SCREEN+1 jmp breturn - //SEG15 main::@return + //SEG12 main::@return breturn: - //SEG16 [8] return + //SEG13 [6] return rts } REGISTER UPLIFT POTENTIAL REGISTERS -Statement [0] (struct Point) point#0 ← {} [ point#0 ] ( ) always clobbers reg byte a -Statement [4] (struct Point) point#0.x ← (byte) 2 [ point#0 ] ( main:2 [ point#0 ] ) always clobbers reg byte a -Statement [5] (struct Point) point#0.y ← (byte) 3 [ point#0 ] ( main:2 [ point#0 ] ) always clobbers reg byte a -Statement [6] *((const byte*) main::SCREEN#0) ← (struct Point) point#0.x [ point#0 ] ( main:2 [ point#0 ] ) always clobbers reg byte a -Statement [7] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point#0.y [ ] ( main:2 [ ] ) always clobbers reg byte a -Potential registers zp ZP_STRUCT:2 [ point#0 ] : zp ZP_STRUCT:2 , +Statement [4] *((const byte*) main::SCREEN#0) ← (const byte) point_x#1 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point_y#1 [ ] ( main:2 [ ] ) always clobbers reg byte a REGISTER UPLIFT SCOPES -Uplift Scope [] 0.4: zp ZP_STRUCT:2 [ point#0 ] Uplift Scope [Point] Uplift Scope [main] +Uplift Scope [] -Uplifting [] best 53 combination zp ZP_STRUCT:2 [ point#0 ] -Uplifting [Point] best 53 combination -Uplifting [main] best 53 combination +Uplifting [Point] best 33 combination +Uplifting [main] best 33 combination +Uplifting [] best 33 combination ASSEMBLER BEFORE OPTIMIZATION //SEG0 File Comments @@ -189,44 +219,35 @@ ASSEMBLER BEFORE OPTIMIZATION :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels - .label point = 2 + .const point_x = 2 + .const point_y = 3 //SEG3 @begin bbegin: -//SEG4 [0] (struct Point) point#0 ← {} -- vssz1=vssf2 - lda #0 - sta point - sta point+1 -//SEG5 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] b1_from_bbegin: jmp b1 -//SEG6 @1 +//SEG5 @1 b1: -//SEG7 [2] call main +//SEG6 [2] call main jsr main -//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG7 [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: jmp bend -//SEG9 @end +//SEG8 @end bend: -//SEG10 main +//SEG9 main main: { .label SCREEN = $400 - //SEG11 [4] (struct Point) point#0.x ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta point+0 - //SEG12 [5] (struct Point) point#0.y ← (byte) 3 -- vbuz1=vbuc1 - lda #3 - sta point+1 - //SEG13 [6] *((const byte*) main::SCREEN#0) ← (struct Point) point#0.x -- _deref_pbuc1=vbuz1 - lda point+0 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) point_x#1 -- _deref_pbuc1=vbuc2 + lda #point_x sta SCREEN - //SEG14 [7] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point#0.y -- _deref_pbuc1=vbuz1 - lda point+1 + //SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point_y#1 -- _deref_pbuc1=vbuc2 + lda #point_y sta SCREEN+1 jmp breturn - //SEG15 main::@return + //SEG12 main::@return breturn: - //SEG16 [8] return + //SEG13 [6] return rts } @@ -236,14 +257,17 @@ Removing instruction jmp bend Removing instruction jmp breturn Succesful ASM optimization Pass5NextJumpElimination Removing instruction b1_from_bbegin: +Removing instruction b1: Removing instruction bend_from_b1: Succesful ASM optimization Pass5RedundantLabelElimination -Removing instruction b1: Removing instruction bend: Removing instruction breturn: Succesful ASM optimization Pass5UnusedLabelElimination -Adding RTS to root block -Succesful ASM optimization Pass5AddMainRts +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE (label) @1 @@ -256,52 +280,42 @@ FINAL SYMBOL TABLE (byte*) main::SCREEN (const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 (struct Point) point -(struct Point) point#0 point zp ZP_STRUCT:2 0.4 +(byte) point_x +(const byte) point_x#1 point_x = (byte) 2 +(byte) point_y +(const byte) point_y#1 point_y = (byte) 3 -zp ZP_STRUCT:2 [ point#0 ] FINAL ASSEMBLER -Score: 50 +Score: 18 //SEG0 File Comments // Minimal struct - declaration, instantiation and usage //SEG1 Basic Upstart .pc = $801 "Basic" -:BasicUpstart(bbegin) +:BasicUpstart(main) .pc = $80d "Program" //SEG2 Global Constants & labels - .label point = 2 + .const point_x = 2 + .const point_y = 3 //SEG3 @begin -bbegin: -//SEG4 [0] (struct Point) point#0 ← {} -- vssz1=vssf2 - lda #0 - sta point - sta point+1 -//SEG5 [1] phi from @begin to @1 [phi:@begin->@1] -//SEG6 @1 -//SEG7 [2] call main - jsr main - rts -//SEG8 [3] phi from @1 to @end [phi:@1->@end] -//SEG9 @end -//SEG10 main +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main main: { .label SCREEN = $400 - //SEG11 [4] (struct Point) point#0.x ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta point+0 - //SEG12 [5] (struct Point) point#0.y ← (byte) 3 -- vbuz1=vbuc1 - lda #3 - sta point+1 - //SEG13 [6] *((const byte*) main::SCREEN#0) ← (struct Point) point#0.x -- _deref_pbuc1=vbuz1 - lda point+0 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) point_x#1 -- _deref_pbuc1=vbuc2 + lda #point_x sta SCREEN - //SEG14 [7] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point#0.y -- _deref_pbuc1=vbuz1 - lda point+1 + //SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point_y#1 -- _deref_pbuc1=vbuc2 + lda #point_y sta SCREEN+1 - //SEG15 main::@return - //SEG16 [8] return + //SEG12 main::@return + //SEG13 [6] return rts } diff --git a/src/test/ref/struct-1.asm b/src/test/ref/struct-1.asm index b4b8782b8..6c9eb949a 100644 --- a/src/test/ref/struct-1.asm +++ b/src/test/ref/struct-1.asm @@ -1,29 +1,14 @@ // Minimal struct - two instances being used. .pc = $801 "Basic" -:BasicUpstart(bbegin) +:BasicUpstart(main) .pc = $80d "Program" - .label point1 = 2 - .label point2 = 4 -bbegin: - lda #0 - sta point1 - sta point1+1 - sta point2 - sta point2+1 - jsr main - rts + .const point1_x = 2 + .const point1_y = 3 main: { .label SCREEN = $400 - lda #2 - sta point1+0 - lda #3 - sta point1+1 - sta point2+0 - lda point1+0 - sta point2+1 - lda point2+0 + lda #point1_y sta SCREEN - lda point2+1 + lda #point1_x sta SCREEN+1 rts } diff --git a/src/test/ref/struct-1.cfg b/src/test/ref/struct-1.cfg index facbf19a5..d16c31a29 100644 --- a/src/test/ref/struct-1.cfg +++ b/src/test/ref/struct-1.cfg @@ -1,21 +1,16 @@ @begin: scope:[] from - [0] (struct Point) point1#0 ← {} - [1] (struct Point) point2#0 ← {} + [0] phi() to:@1 @1: scope:[] from @begin - [2] phi() - [3] call main + [1] phi() + [2] call main to:@end @end: scope:[] from @1 - [4] phi() + [3] phi() main: scope:[main] from @1 - [5] (struct Point) point1#0.x ← (byte) 2 - [6] (struct Point) point1#0.y ← (byte) 3 - [7] (struct Point) point2#0.x ← (struct Point) point1#0.y - [8] (struct Point) point2#0.y ← (struct Point) point1#0.x - [9] *((const byte*) main::SCREEN#0) ← (struct Point) point2#0.x - [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point2#0.y + [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_y#1 + [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_x#1 to:main::@return main::@return: scope:[main] from main - [11] return + [6] return to:@return diff --git a/src/test/ref/struct-1.log b/src/test/ref/struct-1.log index 37264d7fe..8d56fbebd 100644 --- a/src/test/ref/struct-1.log +++ b/src/test/ref/struct-1.log @@ -1,30 +1,66 @@ +Created struct value member variable (byte) point1_x +Created struct value member variable (byte) point1_y +Converted struct value to member variables (struct Point) point1 +Created struct value member variable (byte) point2_x +Created struct value member variable (byte) point2_y +Converted struct value to member variables (struct Point) point2 +Adding struct value member variable default initializer (byte) point1_x ← (byte) 0 +Adding struct value member variable default initializer (byte) point1_y ← (byte) 0 +Adding struct value member variable default initializer (byte) point2_x ← (byte) 0 +Adding struct value member variable default initializer (byte) point2_y ← (byte) 0 +Replacing struct member reference (struct Point) point1.x with member variable reference (byte) point1_x +Replacing struct member reference (struct Point) point1.y with member variable reference (byte) point1_y +Replacing struct member reference (struct Point) point1.y with member variable reference (byte) point1_y +Replacing struct member reference (struct Point) point2.x with member variable reference (byte) point2_x +Replacing struct member reference (struct Point) point1.x with member variable reference (byte) point1_x +Replacing struct member reference (struct Point) point2.y with member variable reference (byte) point2_y +Replacing struct member reference (struct Point) point2.x with member variable reference (byte) point2_x +Replacing struct member reference (struct Point) point2.y with member variable reference (byte) point2_y Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 CONTROL FLOW GRAPH SSA @begin: scope:[] from - (struct Point) point1#0 ← {} - (struct Point) point2#0 ← {} + (byte) point1_x#0 ← (byte) 0 + (byte) point1_y#0 ← (byte) 0 + (byte) point2_x#0 ← (byte) 0 + (byte) point2_y#0 ← (byte) 0 to:@1 main: scope:[main] from @1 - (struct Point) point2#1 ← phi( @1/(struct Point) point2#2 ) - (struct Point) point1#1 ← phi( @1/(struct Point) point1#2 ) - (struct Point) point1#1.x ← (number) 2 - (struct Point) point1#1.y ← (number) 3 - (struct Point) point2#1.x ← (struct Point) point1#1.y - (struct Point) point2#1.y ← (struct Point) point1#1.x + (byte) point1_x#1 ← (number) 2 + (byte) point1_y#1 ← (number) 3 + (byte) point2_x#1 ← (byte) point1_y#1 + (byte) point2_y#1 ← (byte) point1_x#1 (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 - *((byte*) main::SCREEN#0 + (number) 0) ← (struct Point) point2#1.x - *((byte*) main::SCREEN#0 + (number) 1) ← (struct Point) point2#1.y + *((byte*) main::SCREEN#0 + (number) 0) ← (byte) point2_x#1 + *((byte*) main::SCREEN#0 + (number) 1) ← (byte) point2_y#1 to:main::@return main::@return: scope:[main] from main + (byte) point2_y#4 ← phi( main/(byte) point2_y#1 ) + (byte) point2_x#4 ← phi( main/(byte) point2_x#1 ) + (byte) point1_y#4 ← phi( main/(byte) point1_y#1 ) + (byte) point1_x#4 ← phi( main/(byte) point1_x#1 ) + (byte) point1_x#2 ← (byte) point1_x#4 + (byte) point1_y#2 ← (byte) point1_y#4 + (byte) point2_x#2 ← (byte) point2_x#4 + (byte) point2_y#2 ← (byte) point2_y#4 return to:@return @1: scope:[] from @begin - (struct Point) point2#2 ← phi( @begin/(struct Point) point2#0 ) - (struct Point) point1#2 ← phi( @begin/(struct Point) point1#0 ) + (byte) point2_y#6 ← phi( @begin/(byte) point2_y#0 ) + (byte) point2_x#6 ← phi( @begin/(byte) point2_x#0 ) + (byte) point1_y#6 ← phi( @begin/(byte) point1_y#0 ) + (byte) point1_x#6 ← phi( @begin/(byte) point1_x#0 ) call main to:@2 @2: scope:[] from @1 + (byte) point2_y#5 ← phi( @1/(byte) point2_y#2 ) + (byte) point2_x#5 ← phi( @1/(byte) point2_x#2 ) + (byte) point1_y#5 ← phi( @1/(byte) point1_y#2 ) + (byte) point1_x#5 ← phi( @1/(byte) point1_x#2 ) + (byte) point1_x#3 ← (byte) point1_x#5 + (byte) point1_y#3 ← (byte) point1_y#5 + (byte) point2_x#3 ← (byte) point2_x#5 + (byte) point2_y#3 ← (byte) point2_y#5 to:@end @end: scope:[] from @2 @@ -40,21 +76,47 @@ SYMBOL TABLE SSA (byte*) main::SCREEN (byte*) main::SCREEN#0 (struct Point) point1 -(struct Point) point1#0 -(struct Point) point1#1 -(struct Point) point1#2 +(byte) point1_x +(byte) point1_x#0 +(byte) point1_x#1 +(byte) point1_x#2 +(byte) point1_x#3 +(byte) point1_x#4 +(byte) point1_x#5 +(byte) point1_x#6 +(byte) point1_y +(byte) point1_y#0 +(byte) point1_y#1 +(byte) point1_y#2 +(byte) point1_y#3 +(byte) point1_y#4 +(byte) point1_y#5 +(byte) point1_y#6 (struct Point) point2 -(struct Point) point2#0 -(struct Point) point2#1 -(struct Point) point2#2 +(byte) point2_x +(byte) point2_x#0 +(byte) point2_x#1 +(byte) point2_x#2 +(byte) point2_x#3 +(byte) point2_x#4 +(byte) point2_x#5 +(byte) point2_x#6 +(byte) point2_y +(byte) point2_y#0 +(byte) point2_y#1 +(byte) point2_y#2 +(byte) point2_y#3 +(byte) point2_y#4 +(byte) point2_y#5 +(byte) point2_y#6 -Adding number conversion cast (unumber) 2 in (struct Point) point1#1.x ← (number) 2 -Adding number conversion cast (unumber) 3 in (struct Point) point1#1.y ← (number) 3 -Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← (struct Point) point2#1.x -Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← (struct Point) point2#1.y +Adding number conversion cast (unumber) 2 in (byte) point1_x#1 ← (number) 2 +Adding number conversion cast (unumber) 3 in (byte) point1_y#1 ← (number) 3 +Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← (byte) point2_x#1 +Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← (byte) point2_y#1 Successful SSA optimization PassNAddNumberTypeConversions -Inlining cast (struct Point) point1#1.x ← (unumber)(number) 2 -Inlining cast (struct Point) point1#1.y ← (unumber)(number) 3 +Inlining cast (byte) point1_x#1 ← (unumber)(number) 2 +Inlining cast (byte) point1_y#1 ← (unumber)(number) 3 Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 Successful SSA optimization Pass2InlineCast Simplifying constant integer cast 2 @@ -68,51 +130,69 @@ Finalized unsigned number type (byte) 3 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 1 Successful SSA optimization PassNFinalizeNumberTypeConversions -Alias (struct Point) point1#0 = (struct Point) point1#2 -Alias (struct Point) point2#0 = (struct Point) point2#2 +Alias (byte) point1_y#1 = (byte) point2_x#1 (byte) point1_y#4 (byte) point2_x#4 (byte) point1_y#2 (byte) point2_x#2 +Alias (byte) point1_x#1 = (byte) point2_y#1 (byte) point1_x#4 (byte) point2_y#4 (byte) point1_x#2 (byte) point2_y#2 +Alias (byte) point1_x#0 = (byte) point1_x#6 +Alias (byte) point1_y#0 = (byte) point1_y#6 +Alias (byte) point2_x#0 = (byte) point2_x#6 +Alias (byte) point2_y#0 = (byte) point2_y#6 +Alias (byte) point1_x#3 = (byte) point1_x#5 +Alias (byte) point1_y#3 = (byte) point1_y#5 +Alias (byte) point2_x#3 = (byte) point2_x#5 +Alias (byte) point2_y#3 = (byte) point2_y#5 Successful SSA optimization Pass2AliasElimination -Identical Phi Values (struct Point) point1#1 (struct Point) point1#0 -Identical Phi Values (struct Point) point2#1 (struct Point) point2#0 +Identical Phi Values (byte) point1_x#3 (byte) point1_x#1 +Identical Phi Values (byte) point1_y#3 (byte) point1_y#1 +Identical Phi Values (byte) point2_x#3 (byte) point1_y#1 +Identical Phi Values (byte) point2_y#3 (byte) point1_x#1 Successful SSA optimization Pass2IdenticalPhiElimination +Constant (const byte) point1_x#0 = 0 +Constant (const byte) point1_y#0 = 0 +Constant (const byte) point2_x#0 = 0 +Constant (const byte) point2_y#0 = 0 +Constant (const byte) point1_x#1 = 2 +Constant (const byte) point1_y#1 = 3 Constant (const byte*) main::SCREEN#0 = (byte*) 1024 Successful SSA optimization Pass2ConstantIdentification -Simplifying expression containing zero main::SCREEN#0 in [8] *((const byte*) main::SCREEN#0 + (byte) 0) ← (struct Point) point2#0.x +Simplifying expression containing zero main::SCREEN#0 in [9] *((const byte*) main::SCREEN#0 + (byte) 0) ← (const byte) point1_y#1 Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused constant (const byte) point1_x#0 +Eliminating unused constant (const byte) point1_y#0 +Eliminating unused constant (const byte) point2_x#0 +Eliminating unused constant (const byte) point2_y#0 +Successful SSA optimization PassNEliminateUnusedVars Consolidated array index constant in *(main::SCREEN#0+1) Successful SSA optimization Pass2ConstantAdditionElimination +Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @2 Adding NOP phi() at start of @end CALL GRAPH -Calls in [] to main:3 +Calls in [] to main:2 Created 0 initial phi equivalence classes Coalesced down to 0 phi equivalence classes Culled Empty Block (label) @2 +Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @end FINAL CONTROL FLOW GRAPH @begin: scope:[] from - [0] (struct Point) point1#0 ← {} - [1] (struct Point) point2#0 ← {} + [0] phi() to:@1 @1: scope:[] from @begin - [2] phi() - [3] call main + [1] phi() + [2] call main to:@end @end: scope:[] from @1 - [4] phi() + [3] phi() main: scope:[main] from @1 - [5] (struct Point) point1#0.x ← (byte) 2 - [6] (struct Point) point1#0.y ← (byte) 3 - [7] (struct Point) point2#0.x ← (struct Point) point1#0.y - [8] (struct Point) point2#0.y ← (struct Point) point1#0.x - [9] *((const byte*) main::SCREEN#0) ← (struct Point) point2#0.x - [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point2#0.y + [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_y#1 + [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_x#1 to:main::@return main::@return: scope:[main] from main - [11] return + [6] return to:@return @@ -122,16 +202,14 @@ VARIABLE REGISTER WEIGHTS (void()) main() (byte*) main::SCREEN (struct Point) point1 -(struct Point) point1#0 0.3333333333333333 +(byte) point1_x +(byte) point1_y (struct Point) point2 -(struct Point) point2#0 0.2857142857142857 +(byte) point2_x +(byte) point2_y Initial phi equivalence classes Complete equivalence classes -[ point1#0 ] -[ point2#0 ] -Allocated zp ZP_STRUCT:2 [ point1#0 ] -Allocated zp ZP_STRUCT:4 [ point2#0 ] INITIAL ASM //SEG0 File Comments @@ -141,78 +219,50 @@ INITIAL ASM :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels - .label point1 = 2 - .label point2 = 4 + .const point1_x = 2 + .const point1_y = 3 //SEG3 @begin bbegin: -//SEG4 [0] (struct Point) point1#0 ← {} -- vssz1=vssf2 - lda #0 - sta point1 - sta point1+1 -//SEG5 [1] (struct Point) point2#0 ← {} -- vssz1=vssf2 - lda #0 - sta point2 - sta point2+1 -//SEG6 [2] phi from @begin to @1 [phi:@begin->@1] +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] b1_from_bbegin: jmp b1 -//SEG7 @1 +//SEG5 @1 b1: -//SEG8 [3] call main +//SEG6 [2] call main jsr main -//SEG9 [4] phi from @1 to @end [phi:@1->@end] +//SEG7 [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: jmp bend -//SEG10 @end +//SEG8 @end bend: -//SEG11 main +//SEG9 main main: { .label SCREEN = $400 - //SEG12 [5] (struct Point) point1#0.x ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta point1+0 - //SEG13 [6] (struct Point) point1#0.y ← (byte) 3 -- vbuz1=vbuc1 - lda #3 - sta point1+1 - //SEG14 [7] (struct Point) point2#0.x ← (struct Point) point1#0.y -- vbuz1=vbuz2 - lda point1+1 - sta point2+0 - //SEG15 [8] (struct Point) point2#0.y ← (struct Point) point1#0.x -- vbuz1=vbuz2 - lda point1+0 - sta point2+1 - //SEG16 [9] *((const byte*) main::SCREEN#0) ← (struct Point) point2#0.x -- _deref_pbuc1=vbuz1 - lda point2+0 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_y#1 -- _deref_pbuc1=vbuc2 + lda #point1_y sta SCREEN - //SEG17 [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point2#0.y -- _deref_pbuc1=vbuz1 - lda point2+1 + //SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_x#1 -- _deref_pbuc1=vbuc2 + lda #point1_x sta SCREEN+1 jmp breturn - //SEG18 main::@return + //SEG12 main::@return breturn: - //SEG19 [11] return + //SEG13 [6] return rts } REGISTER UPLIFT POTENTIAL REGISTERS -Statement [0] (struct Point) point1#0 ← {} [ point1#0 ] ( ) always clobbers reg byte a -Statement [1] (struct Point) point2#0 ← {} [ point1#0 point2#0 ] ( ) always clobbers reg byte a -Statement [5] (struct Point) point1#0.x ← (byte) 2 [ point1#0 point2#0 ] ( main:3 [ point1#0 point2#0 ] ) always clobbers reg byte a -Statement [6] (struct Point) point1#0.y ← (byte) 3 [ point1#0 point2#0 ] ( main:3 [ point1#0 point2#0 ] ) always clobbers reg byte a -Statement [7] (struct Point) point2#0.x ← (struct Point) point1#0.y [ point1#0 point2#0 ] ( main:3 [ point1#0 point2#0 ] ) always clobbers reg byte a -Statement [8] (struct Point) point2#0.y ← (struct Point) point1#0.x [ point2#0 ] ( main:3 [ point2#0 ] ) always clobbers reg byte a -Statement [9] *((const byte*) main::SCREEN#0) ← (struct Point) point2#0.x [ point2#0 ] ( main:3 [ point2#0 ] ) always clobbers reg byte a -Statement [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point2#0.y [ ] ( main:3 [ ] ) always clobbers reg byte a -Potential registers zp ZP_STRUCT:2 [ point1#0 ] : zp ZP_STRUCT:2 , -Potential registers zp ZP_STRUCT:4 [ point2#0 ] : zp ZP_STRUCT:4 , +Statement [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_y#1 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_x#1 [ ] ( main:2 [ ] ) always clobbers reg byte a REGISTER UPLIFT SCOPES -Uplift Scope [] 0.33: zp ZP_STRUCT:2 [ point1#0 ] 0.29: zp ZP_STRUCT:4 [ point2#0 ] Uplift Scope [Point] Uplift Scope [main] +Uplift Scope [] -Uplifting [] best 73 combination zp ZP_STRUCT:2 [ point1#0 ] zp ZP_STRUCT:4 [ point2#0 ] -Uplifting [Point] best 73 combination -Uplifting [main] best 73 combination +Uplifting [Point] best 33 combination +Uplifting [main] best 33 combination +Uplifting [] best 33 combination ASSEMBLER BEFORE OPTIMIZATION //SEG0 File Comments @@ -222,55 +272,35 @@ ASSEMBLER BEFORE OPTIMIZATION :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels - .label point1 = 2 - .label point2 = 4 + .const point1_x = 2 + .const point1_y = 3 //SEG3 @begin bbegin: -//SEG4 [0] (struct Point) point1#0 ← {} -- vssz1=vssf2 - lda #0 - sta point1 - sta point1+1 -//SEG5 [1] (struct Point) point2#0 ← {} -- vssz1=vssf2 - lda #0 - sta point2 - sta point2+1 -//SEG6 [2] phi from @begin to @1 [phi:@begin->@1] +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] b1_from_bbegin: jmp b1 -//SEG7 @1 +//SEG5 @1 b1: -//SEG8 [3] call main +//SEG6 [2] call main jsr main -//SEG9 [4] phi from @1 to @end [phi:@1->@end] +//SEG7 [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: jmp bend -//SEG10 @end +//SEG8 @end bend: -//SEG11 main +//SEG9 main main: { .label SCREEN = $400 - //SEG12 [5] (struct Point) point1#0.x ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta point1+0 - //SEG13 [6] (struct Point) point1#0.y ← (byte) 3 -- vbuz1=vbuc1 - lda #3 - sta point1+1 - //SEG14 [7] (struct Point) point2#0.x ← (struct Point) point1#0.y -- vbuz1=vbuz2 - lda point1+1 - sta point2+0 - //SEG15 [8] (struct Point) point2#0.y ← (struct Point) point1#0.x -- vbuz1=vbuz2 - lda point1+0 - sta point2+1 - //SEG16 [9] *((const byte*) main::SCREEN#0) ← (struct Point) point2#0.x -- _deref_pbuc1=vbuz1 - lda point2+0 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_y#1 -- _deref_pbuc1=vbuc2 + lda #point1_y sta SCREEN - //SEG17 [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point2#0.y -- _deref_pbuc1=vbuz1 - lda point2+1 + //SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_x#1 -- _deref_pbuc1=vbuc2 + lda #point1_x sta SCREEN+1 jmp breturn - //SEG18 main::@return + //SEG12 main::@return breturn: - //SEG19 [11] return + //SEG13 [6] return rts } @@ -279,18 +309,18 @@ Removing instruction jmp b1 Removing instruction jmp bend Removing instruction jmp breturn Succesful ASM optimization Pass5NextJumpElimination -Removing instruction lda #0 -Removing instruction lda point1+1 -Succesful ASM optimization Pass5UnnecesaryLoadElimination Removing instruction b1_from_bbegin: +Removing instruction b1: Removing instruction bend_from_b1: Succesful ASM optimization Pass5RedundantLabelElimination -Removing instruction b1: Removing instruction bend: Removing instruction breturn: Succesful ASM optimization Pass5UnusedLabelElimination -Adding RTS to root block -Succesful ASM optimization Pass5AddMainRts +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE (label) @1 @@ -303,64 +333,45 @@ FINAL SYMBOL TABLE (byte*) main::SCREEN (const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 (struct Point) point1 -(struct Point) point1#0 point1 zp ZP_STRUCT:2 0.3333333333333333 +(byte) point1_x +(const byte) point1_x#1 point1_x = (byte) 2 +(byte) point1_y +(const byte) point1_y#1 point1_y = (byte) 3 (struct Point) point2 -(struct Point) point2#0 point2 zp ZP_STRUCT:4 0.2857142857142857 +(byte) point2_x +(byte) point2_y -zp ZP_STRUCT:2 [ point1#0 ] -zp ZP_STRUCT:4 [ point2#0 ] FINAL ASSEMBLER -Score: 65 +Score: 18 //SEG0 File Comments // Minimal struct - two instances being used. //SEG1 Basic Upstart .pc = $801 "Basic" -:BasicUpstart(bbegin) +:BasicUpstart(main) .pc = $80d "Program" //SEG2 Global Constants & labels - .label point1 = 2 - .label point2 = 4 + .const point1_x = 2 + .const point1_y = 3 //SEG3 @begin -bbegin: -//SEG4 [0] (struct Point) point1#0 ← {} -- vssz1=vssf2 - lda #0 - sta point1 - sta point1+1 -//SEG5 [1] (struct Point) point2#0 ← {} -- vssz1=vssf2 - sta point2 - sta point2+1 -//SEG6 [2] phi from @begin to @1 [phi:@begin->@1] -//SEG7 @1 -//SEG8 [3] call main - jsr main - rts -//SEG9 [4] phi from @1 to @end [phi:@1->@end] -//SEG10 @end -//SEG11 main +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main main: { .label SCREEN = $400 - //SEG12 [5] (struct Point) point1#0.x ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta point1+0 - //SEG13 [6] (struct Point) point1#0.y ← (byte) 3 -- vbuz1=vbuc1 - lda #3 - sta point1+1 - //SEG14 [7] (struct Point) point2#0.x ← (struct Point) point1#0.y -- vbuz1=vbuz2 - sta point2+0 - //SEG15 [8] (struct Point) point2#0.y ← (struct Point) point1#0.x -- vbuz1=vbuz2 - lda point1+0 - sta point2+1 - //SEG16 [9] *((const byte*) main::SCREEN#0) ← (struct Point) point2#0.x -- _deref_pbuc1=vbuz1 - lda point2+0 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_y#1 -- _deref_pbuc1=vbuc2 + lda #point1_y sta SCREEN - //SEG17 [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point2#0.y -- _deref_pbuc1=vbuz1 - lda point2+1 + //SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_x#1 -- _deref_pbuc1=vbuc2 + lda #point1_x sta SCREEN+1 - //SEG18 main::@return - //SEG19 [11] return + //SEG12 main::@return + //SEG13 [6] return rts } diff --git a/src/test/ref/struct-2.asm b/src/test/ref/struct-2.asm index 29ff684c8..474637832 100644 --- a/src/test/ref/struct-2.asm +++ b/src/test/ref/struct-2.asm @@ -1,36 +1,19 @@ // Minimal struct - different instances and copying .pc = $801 "Basic" -:BasicUpstart(bbegin) +:BasicUpstart(main) .pc = $80d "Program" - .label point1 = 2 - .label point2 = 4 -bbegin: - lda #0 - sta point1 - sta point1+1 - sta point2 - sta point2+1 - jsr main - rts + .const point1_x = 2 + .const point1_y = 3 + .const point2_x = 4 main: { .label SCREEN = $400 - lda #2 - sta point1+0 - lda #3 - sta point1+1 - lda point1 - sta point2 - lda point1+1 - sta point2+1 - lda #4 - sta point2+0 - lda point1+0 + lda #point1_x sta SCREEN - lda point1+1 + lda #point1_y sta SCREEN+1 - lda point2+0 + lda #point2_x sta SCREEN+2 - lda point2+1 + lda #point1_y sta SCREEN+3 rts } diff --git a/src/test/ref/struct-2.cfg b/src/test/ref/struct-2.cfg index 1783d01c8..4ea32347d 100644 --- a/src/test/ref/struct-2.cfg +++ b/src/test/ref/struct-2.cfg @@ -1,23 +1,18 @@ @begin: scope:[] from - [0] (struct Point) point1#0 ← {} - [1] (struct Point) point2#0 ← {} + [0] phi() to:@1 @1: scope:[] from @begin - [2] phi() - [3] call main + [1] phi() + [2] call main to:@end @end: scope:[] from @1 - [4] phi() + [3] phi() main: scope:[main] from @1 - [5] (struct Point) point1#0.x ← (byte) 2 - [6] (struct Point) point1#0.y ← (byte) 3 - [7] (struct Point) point2#1 ← (struct Point) point1#0 - [8] (struct Point) point2#1.x ← (byte) 4 - [9] *((const byte*) main::SCREEN#0) ← (struct Point) point1#0.x - [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point1#0.y - [11] *((const byte*) main::SCREEN#0+(byte) 2) ← (struct Point) point2#1.x - [12] *((const byte*) main::SCREEN#0+(byte) 3) ← (struct Point) point2#1.y + [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_x#1 + [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_y#1 + [6] *((const byte*) main::SCREEN#0+(byte) 2) ← (const byte) point2_x#2 + [7] *((const byte*) main::SCREEN#0+(byte) 3) ← (const byte) point1_y#1 to:main::@return main::@return: scope:[main] from main - [13] return + [8] return to:@return diff --git a/src/test/ref/struct-2.log b/src/test/ref/struct-2.log index 8e03c36f0..8a60650ee 100644 --- a/src/test/ref/struct-2.log +++ b/src/test/ref/struct-2.log @@ -1,35 +1,70 @@ +Created struct value member variable (byte) point1_x +Created struct value member variable (byte) point1_y +Converted struct value to member variables (struct Point) point1 +Created struct value member variable (byte) point2_x +Created struct value member variable (byte) point2_y +Converted struct value to member variables (struct Point) point2 +Adding struct value member variable default initializer (byte) point1_x ← (byte) 0 +Adding struct value member variable default initializer (byte) point1_y ← (byte) 0 +Adding struct value member variable default initializer (byte) point2_x ← (byte) 0 +Adding struct value member variable default initializer (byte) point2_y ← (byte) 0 +Adding struct value member variable copy (byte) point2_x ← (byte) point1_x +Adding struct value member variable copy (byte) point2_y ← (byte) point1_y +Replacing struct member reference (struct Point) point1.x with member variable reference (byte) point1_x +Replacing struct member reference (struct Point) point1.y with member variable reference (byte) point1_y +Replacing struct member reference (struct Point) point2.x with member variable reference (byte) point2_x +Replacing struct member reference (struct Point) point1.x with member variable reference (byte) point1_x +Replacing struct member reference (struct Point) point1.y with member variable reference (byte) point1_y +Replacing struct member reference (struct Point) point2.x with member variable reference (byte) point2_x +Replacing struct member reference (struct Point) point2.y with member variable reference (byte) point2_y Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 CONTROL FLOW GRAPH SSA @begin: scope:[] from - (struct Point) point1#0 ← {} - (struct Point) point2#0 ← {} + (byte) point1_x#0 ← (byte) 0 + (byte) point1_y#0 ← (byte) 0 + (byte) point2_x#0 ← (byte) 0 + (byte) point2_y#0 ← (byte) 0 to:@1 main: scope:[main] from @1 - (struct Point) point1#1 ← phi( @1/(struct Point) point1#2 ) - (struct Point) point1#1.x ← (number) 2 - (struct Point) point1#1.y ← (number) 3 - (struct Point) point2#1 ← (struct Point) point1#1 - (struct Point) point2#1.x ← (number) 4 + (byte) point1_x#1 ← (number) 2 + (byte) point1_y#1 ← (number) 3 + (byte) point2_x#1 ← (byte) point1_x#1 + (byte) point2_y#1 ← (byte) point1_y#1 + (byte) point2_x#2 ← (number) 4 (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 - *((byte*) main::SCREEN#0 + (number) 0) ← (struct Point) point1#1.x - *((byte*) main::SCREEN#0 + (number) 1) ← (struct Point) point1#1.y - *((byte*) main::SCREEN#0 + (number) 2) ← (struct Point) point2#1.x - *((byte*) main::SCREEN#0 + (number) 3) ← (struct Point) point2#1.y + *((byte*) main::SCREEN#0 + (number) 0) ← (byte) point1_x#1 + *((byte*) main::SCREEN#0 + (number) 1) ← (byte) point1_y#1 + *((byte*) main::SCREEN#0 + (number) 2) ← (byte) point2_x#2 + *((byte*) main::SCREEN#0 + (number) 3) ← (byte) point2_y#1 to:main::@return main::@return: scope:[main] from main - (struct Point) point2#4 ← phi( main/(struct Point) point2#1 ) - (struct Point) point2#2 ← (struct Point) point2#4 + (byte) point2_y#4 ← phi( main/(byte) point2_y#1 ) + (byte) point2_x#5 ← phi( main/(byte) point2_x#2 ) + (byte) point1_y#4 ← phi( main/(byte) point1_y#1 ) + (byte) point1_x#4 ← phi( main/(byte) point1_x#1 ) + (byte) point1_x#2 ← (byte) point1_x#4 + (byte) point1_y#2 ← (byte) point1_y#4 + (byte) point2_x#3 ← (byte) point2_x#5 + (byte) point2_y#2 ← (byte) point2_y#4 return to:@return @1: scope:[] from @begin - (struct Point) point2#6 ← phi( @begin/(struct Point) point2#0 ) - (struct Point) point1#2 ← phi( @begin/(struct Point) point1#0 ) + (byte) point2_y#6 ← phi( @begin/(byte) point2_y#0 ) + (byte) point2_x#7 ← phi( @begin/(byte) point2_x#0 ) + (byte) point1_y#6 ← phi( @begin/(byte) point1_y#0 ) + (byte) point1_x#6 ← phi( @begin/(byte) point1_x#0 ) call main to:@2 @2: scope:[] from @1 - (struct Point) point2#5 ← phi( @1/(struct Point) point2#2 ) - (struct Point) point2#3 ← (struct Point) point2#5 + (byte) point2_y#5 ← phi( @1/(byte) point2_y#2 ) + (byte) point2_x#6 ← phi( @1/(byte) point2_x#3 ) + (byte) point1_y#5 ← phi( @1/(byte) point1_y#2 ) + (byte) point1_x#5 ← phi( @1/(byte) point1_x#2 ) + (byte) point1_x#3 ← (byte) point1_x#5 + (byte) point1_y#3 ← (byte) point1_y#5 + (byte) point2_x#4 ← (byte) point2_x#6 + (byte) point2_y#3 ← (byte) point2_y#5 to:@end @end: scope:[] from @2 @@ -45,29 +80,52 @@ SYMBOL TABLE SSA (byte*) main::SCREEN (byte*) main::SCREEN#0 (struct Point) point1 -(struct Point) point1#0 -(struct Point) point1#1 -(struct Point) point1#2 +(byte) point1_x +(byte) point1_x#0 +(byte) point1_x#1 +(byte) point1_x#2 +(byte) point1_x#3 +(byte) point1_x#4 +(byte) point1_x#5 +(byte) point1_x#6 +(byte) point1_y +(byte) point1_y#0 +(byte) point1_y#1 +(byte) point1_y#2 +(byte) point1_y#3 +(byte) point1_y#4 +(byte) point1_y#5 +(byte) point1_y#6 (struct Point) point2 -(struct Point) point2#0 -(struct Point) point2#1 -(struct Point) point2#2 -(struct Point) point2#3 -(struct Point) point2#4 -(struct Point) point2#5 -(struct Point) point2#6 +(byte) point2_x +(byte) point2_x#0 +(byte) point2_x#1 +(byte) point2_x#2 +(byte) point2_x#3 +(byte) point2_x#4 +(byte) point2_x#5 +(byte) point2_x#6 +(byte) point2_x#7 +(byte) point2_y +(byte) point2_y#0 +(byte) point2_y#1 +(byte) point2_y#2 +(byte) point2_y#3 +(byte) point2_y#4 +(byte) point2_y#5 +(byte) point2_y#6 -Adding number conversion cast (unumber) 2 in (struct Point) point1#1.x ← (number) 2 -Adding number conversion cast (unumber) 3 in (struct Point) point1#1.y ← (number) 3 -Adding number conversion cast (unumber) 4 in (struct Point) point2#1.x ← (number) 4 -Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← (struct Point) point1#1.x -Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← (struct Point) point1#1.y -Adding number conversion cast (unumber) 2 in *((byte*) main::SCREEN#0 + (number) 2) ← (struct Point) point2#1.x -Adding number conversion cast (unumber) 3 in *((byte*) main::SCREEN#0 + (number) 3) ← (struct Point) point2#1.y +Adding number conversion cast (unumber) 2 in (byte) point1_x#1 ← (number) 2 +Adding number conversion cast (unumber) 3 in (byte) point1_y#1 ← (number) 3 +Adding number conversion cast (unumber) 4 in (byte) point2_x#2 ← (number) 4 +Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← (byte) point1_x#1 +Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← (byte) point1_y#1 +Adding number conversion cast (unumber) 2 in *((byte*) main::SCREEN#0 + (number) 2) ← (byte) point2_x#2 +Adding number conversion cast (unumber) 3 in *((byte*) main::SCREEN#0 + (number) 3) ← (byte) point2_y#1 Successful SSA optimization PassNAddNumberTypeConversions -Inlining cast (struct Point) point1#1.x ← (unumber)(number) 2 -Inlining cast (struct Point) point1#1.y ← (unumber)(number) 3 -Inlining cast (struct Point) point2#1.x ← (unumber)(number) 4 +Inlining cast (byte) point1_x#1 ← (unumber)(number) 2 +Inlining cast (byte) point1_y#1 ← (unumber)(number) 3 +Inlining cast (byte) point2_x#2 ← (unumber)(number) 4 Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 Successful SSA optimization Pass2InlineCast Simplifying constant integer cast 2 @@ -87,61 +145,75 @@ Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 3 Successful SSA optimization PassNFinalizeNumberTypeConversions -Alias candidate removed (volatile)(struct Point) point2#1 = (struct Point) point1#1 (struct Point) point2#4 (struct Point) point2#2 -Alias (struct Point) point1#0 = (struct Point) point1#2 -Alias (struct Point) point2#0 = (struct Point) point2#6 -Alias (struct Point) point2#3 = (struct Point) point2#5 +Alias (byte) point1_x#1 = (byte) point2_x#1 (byte) point1_x#4 (byte) point1_x#2 +Alias (byte) point1_y#1 = (byte) point2_y#1 (byte) point1_y#4 (byte) point2_y#4 (byte) point1_y#2 (byte) point2_y#2 +Alias (byte) point2_x#2 = (byte) point2_x#5 (byte) point2_x#3 +Alias (byte) point1_x#0 = (byte) point1_x#6 +Alias (byte) point1_y#0 = (byte) point1_y#6 +Alias (byte) point2_x#0 = (byte) point2_x#7 +Alias (byte) point2_y#0 = (byte) point2_y#6 +Alias (byte) point1_x#3 = (byte) point1_x#5 +Alias (byte) point1_y#3 = (byte) point1_y#5 +Alias (byte) point2_x#4 = (byte) point2_x#6 +Alias (byte) point2_y#3 = (byte) point2_y#5 Successful SSA optimization Pass2AliasElimination -Alias candidate removed (volatile)(struct Point) point2#1 = (struct Point) point1#1 (struct Point) point2#4 (struct Point) point2#2 -Identical Phi Values (struct Point) point1#1 (struct Point) point1#0 -Identical Phi Values (struct Point) point2#4 (struct Point) point2#1 -Identical Phi Values (struct Point) point2#3 (struct Point) point2#2 +Identical Phi Values (byte) point1_x#3 (byte) point1_x#1 +Identical Phi Values (byte) point1_y#3 (byte) point1_y#1 +Identical Phi Values (byte) point2_x#4 (byte) point2_x#2 +Identical Phi Values (byte) point2_y#3 (byte) point1_y#1 Successful SSA optimization Pass2IdenticalPhiElimination +Constant (const byte) point1_x#0 = 0 +Constant (const byte) point1_y#0 = 0 +Constant (const byte) point2_x#0 = 0 +Constant (const byte) point2_y#0 = 0 +Constant (const byte) point1_x#1 = 2 +Constant (const byte) point1_y#1 = 3 +Constant (const byte) point2_x#2 = 4 Constant (const byte*) main::SCREEN#0 = (byte*) 1024 Successful SSA optimization Pass2ConstantIdentification -Simplifying expression containing zero main::SCREEN#0 in [8] *((const byte*) main::SCREEN#0 + (byte) 0) ← (struct Point) point1#0.x +Simplifying expression containing zero main::SCREEN#0 in [10] *((const byte*) main::SCREEN#0 + (byte) 0) ← (const byte) point1_x#1 Successful SSA optimization PassNSimplifyExpressionWithZero -Alias (struct Point) point2#1 = (struct Point) point2#2 -Successful SSA optimization Pass2AliasElimination +Eliminating unused constant (const byte) point1_x#0 +Eliminating unused constant (const byte) point1_y#0 +Eliminating unused constant (const byte) point2_x#0 +Eliminating unused constant (const byte) point2_y#0 +Successful SSA optimization PassNEliminateUnusedVars Consolidated array index constant in *(main::SCREEN#0+1) Consolidated array index constant in *(main::SCREEN#0+2) Consolidated array index constant in *(main::SCREEN#0+3) Successful SSA optimization Pass2ConstantAdditionElimination +Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @2 Adding NOP phi() at start of @end CALL GRAPH -Calls in [] to main:3 +Calls in [] to main:2 Created 0 initial phi equivalence classes Coalesced down to 0 phi equivalence classes Culled Empty Block (label) @2 +Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @end FINAL CONTROL FLOW GRAPH @begin: scope:[] from - [0] (struct Point) point1#0 ← {} - [1] (struct Point) point2#0 ← {} + [0] phi() to:@1 @1: scope:[] from @begin - [2] phi() - [3] call main + [1] phi() + [2] call main to:@end @end: scope:[] from @1 - [4] phi() + [3] phi() main: scope:[main] from @1 - [5] (struct Point) point1#0.x ← (byte) 2 - [6] (struct Point) point1#0.y ← (byte) 3 - [7] (struct Point) point2#1 ← (struct Point) point1#0 - [8] (struct Point) point2#1.x ← (byte) 4 - [9] *((const byte*) main::SCREEN#0) ← (struct Point) point1#0.x - [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point1#0.y - [11] *((const byte*) main::SCREEN#0+(byte) 2) ← (struct Point) point2#1.x - [12] *((const byte*) main::SCREEN#0+(byte) 3) ← (struct Point) point2#1.y + [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_x#1 + [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_y#1 + [6] *((const byte*) main::SCREEN#0+(byte) 2) ← (const byte) point2_x#2 + [7] *((const byte*) main::SCREEN#0+(byte) 3) ← (const byte) point1_y#1 to:main::@return main::@return: scope:[main] from main - [13] return + [8] return to:@return @@ -151,18 +223,14 @@ VARIABLE REGISTER WEIGHTS (void()) main() (byte*) main::SCREEN (struct Point) point1 -(struct Point) point1#0 0.5 +(byte) point1_x +(byte) point1_y (struct Point) point2 -(struct Point) point2#0 20.0 -(struct Point) point2#1 0.4 +(byte) point2_x +(byte) point2_y Initial phi equivalence classes -Coalescing volatile variable equivalence classes [ point2#0 ] and [ point2#1 ] Complete equivalence classes -[ point1#0 ] -[ point2#0 point2#1 ] -Allocated zp ZP_STRUCT:2 [ point1#0 ] -Allocated zp ZP_STRUCT:4 [ point2#0 point2#1 ] INITIAL ASM //SEG0 File Comments @@ -172,88 +240,59 @@ INITIAL ASM :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels - .label point1 = 2 - .label point2 = 4 + .const point1_x = 2 + .const point1_y = 3 + .const point2_x = 4 //SEG3 @begin bbegin: -//SEG4 [0] (struct Point) point1#0 ← {} -- vssz1=vssf2 - lda #0 - sta point1 - sta point1+1 -//SEG5 [1] (struct Point) point2#0 ← {} -- vssz1=vssf2 - lda #0 - sta point2 - sta point2+1 -//SEG6 [2] phi from @begin to @1 [phi:@begin->@1] +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] b1_from_bbegin: jmp b1 -//SEG7 @1 +//SEG5 @1 b1: -//SEG8 [3] call main +//SEG6 [2] call main jsr main -//SEG9 [4] phi from @1 to @end [phi:@1->@end] +//SEG7 [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: jmp bend -//SEG10 @end +//SEG8 @end bend: -//SEG11 main +//SEG9 main main: { .label SCREEN = $400 - //SEG12 [5] (struct Point) point1#0.x ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta point1+0 - //SEG13 [6] (struct Point) point1#0.y ← (byte) 3 -- vbuz1=vbuc1 - lda #3 - sta point1+1 - //SEG14 [7] (struct Point) point2#1 ← (struct Point) point1#0 -- vssz1=vssz2 - lda point1 - sta point2 - lda point1+1 - sta point2+1 - //SEG15 [8] (struct Point) point2#1.x ← (byte) 4 -- vbuz1=vbuc1 - lda #4 - sta point2+0 - //SEG16 [9] *((const byte*) main::SCREEN#0) ← (struct Point) point1#0.x -- _deref_pbuc1=vbuz1 - lda point1+0 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_x#1 -- _deref_pbuc1=vbuc2 + lda #point1_x sta SCREEN - //SEG17 [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point1#0.y -- _deref_pbuc1=vbuz1 - lda point1+1 + //SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_y#1 -- _deref_pbuc1=vbuc2 + lda #point1_y sta SCREEN+1 - //SEG18 [11] *((const byte*) main::SCREEN#0+(byte) 2) ← (struct Point) point2#1.x -- _deref_pbuc1=vbuz1 - lda point2+0 + //SEG12 [6] *((const byte*) main::SCREEN#0+(byte) 2) ← (const byte) point2_x#2 -- _deref_pbuc1=vbuc2 + lda #point2_x sta SCREEN+2 - //SEG19 [12] *((const byte*) main::SCREEN#0+(byte) 3) ← (struct Point) point2#1.y -- _deref_pbuc1=vbuz1 - lda point2+1 + //SEG13 [7] *((const byte*) main::SCREEN#0+(byte) 3) ← (const byte) point1_y#1 -- _deref_pbuc1=vbuc2 + lda #point1_y sta SCREEN+3 jmp breturn - //SEG20 main::@return + //SEG14 main::@return breturn: - //SEG21 [13] return + //SEG15 [8] return rts } REGISTER UPLIFT POTENTIAL REGISTERS -Statement [0] (struct Point) point1#0 ← {} [ point1#0 ] ( ) always clobbers reg byte a -Statement [1] (struct Point) point2#0 ← {} [ point1#0 ] ( ) always clobbers reg byte a -Statement [5] (struct Point) point1#0.x ← (byte) 2 [ point1#0 ] ( main:3 [ point1#0 ] ) always clobbers reg byte a -Statement [6] (struct Point) point1#0.y ← (byte) 3 [ point1#0 ] ( main:3 [ point1#0 ] ) always clobbers reg byte a -Statement [7] (struct Point) point2#1 ← (struct Point) point1#0 [ point1#0 point2#1 ] ( main:3 [ point1#0 point2#1 ] ) always clobbers reg byte a -Statement [8] (struct Point) point2#1.x ← (byte) 4 [ point1#0 point2#1 ] ( main:3 [ point1#0 point2#1 ] ) always clobbers reg byte a -Statement [9] *((const byte*) main::SCREEN#0) ← (struct Point) point1#0.x [ point1#0 point2#1 ] ( main:3 [ point1#0 point2#1 ] ) always clobbers reg byte a -Statement [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point1#0.y [ point2#1 ] ( main:3 [ point2#1 ] ) always clobbers reg byte a -Statement [11] *((const byte*) main::SCREEN#0+(byte) 2) ← (struct Point) point2#1.x [ point2#1 ] ( main:3 [ point2#1 ] ) always clobbers reg byte a -Statement [12] *((const byte*) main::SCREEN#0+(byte) 3) ← (struct Point) point2#1.y [ ] ( main:3 [ ] ) always clobbers reg byte a -Potential registers zp ZP_STRUCT:2 [ point1#0 ] : zp ZP_STRUCT:2 , -Potential registers zp ZP_STRUCT:4 [ point2#0 point2#1 ] : zp ZP_STRUCT:4 , +Statement [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_x#1 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_y#1 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [6] *((const byte*) main::SCREEN#0+(byte) 2) ← (const byte) point2_x#2 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [7] *((const byte*) main::SCREEN#0+(byte) 3) ← (const byte) point1_y#1 [ ] ( main:2 [ ] ) always clobbers reg byte a REGISTER UPLIFT SCOPES -Uplift Scope [] 20.4: zp ZP_STRUCT:4 [ point2#0 point2#1 ] 0.5: zp ZP_STRUCT:2 [ point1#0 ] Uplift Scope [Point] Uplift Scope [main] +Uplift Scope [] -Uplifting [] best 92 combination zp ZP_STRUCT:4 [ point2#0 point2#1 ] zp ZP_STRUCT:2 [ point1#0 ] -Uplifting [Point] best 92 combination -Uplifting [main] best 92 combination +Uplifting [Point] best 45 combination +Uplifting [main] best 45 combination +Uplifting [] best 45 combination ASSEMBLER BEFORE OPTIMIZATION //SEG0 File Comments @@ -263,63 +302,42 @@ ASSEMBLER BEFORE OPTIMIZATION :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels - .label point1 = 2 - .label point2 = 4 + .const point1_x = 2 + .const point1_y = 3 + .const point2_x = 4 //SEG3 @begin bbegin: -//SEG4 [0] (struct Point) point1#0 ← {} -- vssz1=vssf2 - lda #0 - sta point1 - sta point1+1 -//SEG5 [1] (struct Point) point2#0 ← {} -- vssz1=vssf2 - lda #0 - sta point2 - sta point2+1 -//SEG6 [2] phi from @begin to @1 [phi:@begin->@1] +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] b1_from_bbegin: jmp b1 -//SEG7 @1 +//SEG5 @1 b1: -//SEG8 [3] call main +//SEG6 [2] call main jsr main -//SEG9 [4] phi from @1 to @end [phi:@1->@end] +//SEG7 [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: jmp bend -//SEG10 @end +//SEG8 @end bend: -//SEG11 main +//SEG9 main main: { .label SCREEN = $400 - //SEG12 [5] (struct Point) point1#0.x ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta point1+0 - //SEG13 [6] (struct Point) point1#0.y ← (byte) 3 -- vbuz1=vbuc1 - lda #3 - sta point1+1 - //SEG14 [7] (struct Point) point2#1 ← (struct Point) point1#0 -- vssz1=vssz2 - lda point1 - sta point2 - lda point1+1 - sta point2+1 - //SEG15 [8] (struct Point) point2#1.x ← (byte) 4 -- vbuz1=vbuc1 - lda #4 - sta point2+0 - //SEG16 [9] *((const byte*) main::SCREEN#0) ← (struct Point) point1#0.x -- _deref_pbuc1=vbuz1 - lda point1+0 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_x#1 -- _deref_pbuc1=vbuc2 + lda #point1_x sta SCREEN - //SEG17 [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point1#0.y -- _deref_pbuc1=vbuz1 - lda point1+1 + //SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_y#1 -- _deref_pbuc1=vbuc2 + lda #point1_y sta SCREEN+1 - //SEG18 [11] *((const byte*) main::SCREEN#0+(byte) 2) ← (struct Point) point2#1.x -- _deref_pbuc1=vbuz1 - lda point2+0 + //SEG12 [6] *((const byte*) main::SCREEN#0+(byte) 2) ← (const byte) point2_x#2 -- _deref_pbuc1=vbuc2 + lda #point2_x sta SCREEN+2 - //SEG19 [12] *((const byte*) main::SCREEN#0+(byte) 3) ← (struct Point) point2#1.y -- _deref_pbuc1=vbuz1 - lda point2+1 + //SEG13 [7] *((const byte*) main::SCREEN#0+(byte) 3) ← (const byte) point1_y#1 -- _deref_pbuc1=vbuc2 + lda #point1_y sta SCREEN+3 jmp breturn - //SEG20 main::@return + //SEG14 main::@return breturn: - //SEG21 [13] return + //SEG15 [8] return rts } @@ -328,17 +346,18 @@ Removing instruction jmp b1 Removing instruction jmp bend Removing instruction jmp breturn Succesful ASM optimization Pass5NextJumpElimination -Removing instruction lda #0 -Succesful ASM optimization Pass5UnnecesaryLoadElimination Removing instruction b1_from_bbegin: +Removing instruction b1: Removing instruction bend_from_b1: Succesful ASM optimization Pass5RedundantLabelElimination -Removing instruction b1: Removing instruction bend: Removing instruction breturn: Succesful ASM optimization Pass5UnusedLabelElimination -Adding RTS to root block -Succesful ASM optimization Pass5AddMainRts +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE (label) @1 @@ -351,74 +370,53 @@ FINAL SYMBOL TABLE (byte*) main::SCREEN (const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 (struct Point) point1 -(struct Point) point1#0 point1 zp ZP_STRUCT:2 0.5 +(byte) point1_x +(const byte) point1_x#1 point1_x = (byte) 2 +(byte) point1_y +(const byte) point1_y#1 point1_y = (byte) 3 (struct Point) point2 -(struct Point) point2#0 point2 zp ZP_STRUCT:4 20.0 -(struct Point) point2#1 point2 zp ZP_STRUCT:4 0.4 +(byte) point2_x +(const byte) point2_x#2 point2_x = (byte) 4 +(byte) point2_y -zp ZP_STRUCT:2 [ point1#0 ] -zp ZP_STRUCT:4 [ point2#0 point2#1 ] FINAL ASSEMBLER -Score: 87 +Score: 30 //SEG0 File Comments // Minimal struct - different instances and copying //SEG1 Basic Upstart .pc = $801 "Basic" -:BasicUpstart(bbegin) +:BasicUpstart(main) .pc = $80d "Program" //SEG2 Global Constants & labels - .label point1 = 2 - .label point2 = 4 + .const point1_x = 2 + .const point1_y = 3 + .const point2_x = 4 //SEG3 @begin -bbegin: -//SEG4 [0] (struct Point) point1#0 ← {} -- vssz1=vssf2 - lda #0 - sta point1 - sta point1+1 -//SEG5 [1] (struct Point) point2#0 ← {} -- vssz1=vssf2 - sta point2 - sta point2+1 -//SEG6 [2] phi from @begin to @1 [phi:@begin->@1] -//SEG7 @1 -//SEG8 [3] call main - jsr main - rts -//SEG9 [4] phi from @1 to @end [phi:@1->@end] -//SEG10 @end -//SEG11 main +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main main: { .label SCREEN = $400 - //SEG12 [5] (struct Point) point1#0.x ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta point1+0 - //SEG13 [6] (struct Point) point1#0.y ← (byte) 3 -- vbuz1=vbuc1 - lda #3 - sta point1+1 - //SEG14 [7] (struct Point) point2#1 ← (struct Point) point1#0 -- vssz1=vssz2 - lda point1 - sta point2 - lda point1+1 - sta point2+1 - //SEG15 [8] (struct Point) point2#1.x ← (byte) 4 -- vbuz1=vbuc1 - lda #4 - sta point2+0 - //SEG16 [9] *((const byte*) main::SCREEN#0) ← (struct Point) point1#0.x -- _deref_pbuc1=vbuz1 - lda point1+0 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) point1_x#1 -- _deref_pbuc1=vbuc2 + lda #point1_x sta SCREEN - //SEG17 [10] *((const byte*) main::SCREEN#0+(byte) 1) ← (struct Point) point1#0.y -- _deref_pbuc1=vbuz1 - lda point1+1 + //SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← (const byte) point1_y#1 -- _deref_pbuc1=vbuc2 + lda #point1_y sta SCREEN+1 - //SEG18 [11] *((const byte*) main::SCREEN#0+(byte) 2) ← (struct Point) point2#1.x -- _deref_pbuc1=vbuz1 - lda point2+0 + //SEG12 [6] *((const byte*) main::SCREEN#0+(byte) 2) ← (const byte) point2_x#2 -- _deref_pbuc1=vbuc2 + lda #point2_x sta SCREEN+2 - //SEG19 [12] *((const byte*) main::SCREEN#0+(byte) 3) ← (struct Point) point2#1.y -- _deref_pbuc1=vbuz1 - lda point2+1 + //SEG13 [7] *((const byte*) main::SCREEN#0+(byte) 3) ← (const byte) point1_y#1 -- _deref_pbuc1=vbuc2 + lda #point1_y sta SCREEN+3 - //SEG20 main::@return - //SEG21 [13] return + //SEG14 main::@return + //SEG15 [8] return rts } diff --git a/src/test/ref/struct-4.log b/src/test/ref/struct-4.log index 9fc9b1419..41687bb83 100644 --- a/src/test/ref/struct-4.log +++ b/src/test/ref/struct-4.log @@ -1,174 +1,5 @@ -PARSING src/test/kc/struct-4.kc -// 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; - } -} - -STATEMENTS - (struct Point[4]) points ← { fill( 4, 0) } - (byte) SIZEOF_POINT ← (number) 2 - (byte) OFFS_X ← (number) 0 - (byte) OFFS_Y ← (number) 1 -proc (void()) main() - (byte) main:::1::i ← (byte) 0 -main:::1::@1: - (var) main:::1::$0 ← ((byte*)) (struct Point[4]) points - (var) main:::1::$1 ← (var) main:::1::$0 + (byte) OFFS_X - (var) main:::1::$2 ← (byte) main:::1::i * (byte) SIZEOF_POINT - (var) main:::1::$3 ← (var) main:::1::$1 + (var) main:::1::$2 - *((var) main:::1::$3) ← (byte) main:::1::i - (var) main:::1::$4 ← ((byte*)) (struct Point[4]) points - (var) main:::1::$5 ← (var) main:::1::$4 + (byte) OFFS_Y - (var) main:::1::$6 ← (byte) main:::1::i * (byte) SIZEOF_POINT - (var) main:::1::$7 ← (var) main:::1::$5 + (var) main:::1::$6 - (var) main:::1::$8 ← (byte) main:::1::i + (number) 4 - *((var) main:::1::$7) ← (var) main:::1::$8 - (byte) main:::1::i ← (byte) main:::1::i + rangenext(0,3) - (var) main:::1::$9 ← (byte) main:::1::i != rangelast(0,3) - if((var) main:::1::$9) goto main:::1::@1 - (byte*) main::SCREEN ← (number) $400 - (byte) main:::2::i ← (byte) 0 -main:::2::@1: - (var) main:::2::$0 ← ((byte*)) (struct Point[4]) points - (var) main:::2::$1 ← (var) main:::2::$0 + (byte) OFFS_X - (var) main:::2::$2 ← (byte) main:::2::i * (byte) SIZEOF_POINT - (var) main:::2::$3 ← (var) main:::2::$1 + (var) main:::2::$2 - *((byte*) main::SCREEN + (byte) main:::2::i) ← *((var) main:::2::$3) - (var) main:::2::$4 ← (byte*) main::SCREEN + (number) $28 - (var) main:::2::$5 ← ((byte*)) (struct Point[4]) points - (var) main:::2::$6 ← (var) main:::2::$5 + (byte) OFFS_Y - (var) main:::2::$7 ← (byte) main:::2::i * (byte) SIZEOF_POINT - (var) main:::2::$8 ← (var) main:::2::$6 + (var) main:::2::$7 - *((var) main:::2::$4 + (byte) main:::2::i) ← *((var) main:::2::$8) - (byte) main:::2::i ← (byte) main:::2::i + rangenext(0,3) - (var) main:::2::$9 ← (byte) main:::2::i != rangelast(0,3) - if((var) main:::2::$9) goto main:::2::@1 -main::@return: - return -endproc // main() - call main - -SYMBOLS -(label) @1 -(label) @begin -(label) @end -(byte) OFFS_X -(byte) OFFS_Y -(byte) Point::x -(byte) Point::y -(byte) SIZEOF_POINT -(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::@4 -(label) main::@return -(byte*) main::SCREEN -(byte) main::i -(byte) main::i1 -(struct Point[4]) points - Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 -INITIAL CONTROL FLOW GRAPH -@begin: scope:[] from - [0] (struct Point[4]) points ← { fill( 4, 0) } - [1] (byte) SIZEOF_POINT ← (number) 2 - [2] (byte) OFFS_X ← (number) 0 - [3] (byte) OFFS_Y ← (number) 1 - to:@1 -main: scope:[main] from - [4] (byte) main::i ← (byte) 0 - to:main::@1 -main::@1: scope:[main] from main main::@1 - [5] (byte*~) main::$0 ← ((byte*)) (struct Point[4]) points - [6] (byte*~) main::$1 ← (byte*~) main::$0 + (byte) OFFS_X - [7] (byte~) main::$2 ← (byte) main::i * (byte) SIZEOF_POINT - [8] (byte*~) main::$3 ← (byte*~) main::$1 + (byte~) main::$2 - [9] *((byte*~) main::$3) ← (byte) main::i - [10] (byte*~) main::$4 ← ((byte*)) (struct Point[4]) points - [11] (byte*~) main::$5 ← (byte*~) main::$4 + (byte) OFFS_Y - [12] (byte~) main::$6 ← (byte) main::i * (byte) SIZEOF_POINT - [13] (byte*~) main::$7 ← (byte*~) main::$5 + (byte~) main::$6 - [14] (number~) main::$8 ← (byte) main::i + (number) 4 - [15] *((byte*~) main::$7) ← (number~) main::$8 - [16] (byte) main::i ← (byte) main::i + rangenext(0,3) - [17] (bool~) main::$9 ← (byte) main::i != rangelast(0,3) - [18] if((bool~) main::$9) goto main::@1 - to:main::@2 -main::@2: scope:[main] from main::@1 - [19] (byte*) main::SCREEN ← ((byte*)) (number) $400 - [20] (byte) main::i1 ← (byte) 0 - to:main::@3 -main::@3: scope:[main] from main::@2 main::@3 - [21] (byte*~) main::$10 ← ((byte*)) (struct Point[4]) points - [22] (byte*~) main::$11 ← (byte*~) main::$10 + (byte) OFFS_X - [23] (byte~) main::$12 ← (byte) main::i1 * (byte) SIZEOF_POINT - [24] (byte*~) main::$13 ← (byte*~) main::$11 + (byte~) main::$12 - [25] *((byte*) main::SCREEN + (byte) main::i1) ← *((byte*~) main::$13) - [26] (byte*~) main::$14 ← (byte*) main::SCREEN + (number) $28 - [27] (byte*~) main::$15 ← ((byte*)) (struct Point[4]) points - [28] (byte*~) main::$16 ← (byte*~) main::$15 + (byte) OFFS_Y - [29] (byte~) main::$17 ← (byte) main::i1 * (byte) SIZEOF_POINT - [30] (byte*~) main::$18 ← (byte*~) main::$16 + (byte~) main::$17 - [31] *((byte*~) main::$14 + (byte) main::i1) ← *((byte*~) main::$18) - [32] (byte) main::i1 ← (byte) main::i1 + rangenext(0,3) - [33] (bool~) main::$19 ← (byte) main::i1 != rangelast(0,3) - [34] if((bool~) main::$19) goto main::@3 - to:main::@4 -main::@4: scope:[main] from main::@3 - to:main::@return -main::@return: scope:[main] from main::@4 - [35] return - to:@return -@1: scope:[] from @begin - [36] call main - to:@end -@end: scope:[] from @1 - Culled Empty Block (label) main::@4 -PROCEDURE MODIFY VARIABLE ANALYSIS - -Completing Phi functions... CONTROL FLOW GRAPH SSA @begin: scope:[] from diff --git a/src/test/ref/struct-5.log b/src/test/ref/struct-5.log index 11be88fd7..39fb49656 100644 --- a/src/test/ref/struct-5.log +++ b/src/test/ref/struct-5.log @@ -1,169 +1,7 @@ -PARSING src/test/kc/struct-5.kc -// 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; - } -} - -STATEMENTS - (struct Point[4]) points ← { fill( 4, 0) } - (byte) SIZEOF_POINT ← (number) 2 - (byte) OFFS_X ← (number) 0 - (byte) OFFS_Y ← (number) 1 -proc (void()) main() - (byte) main:::1::i ← (byte) 0 -main:::1::@1: - (var) main:::1::$0 ← (struct Point[4]) points + (byte) main:::1::i - (struct Point*) main:::1::point_i ← (var) main:::1::$0 - (var) main:::1::$1 ← ((byte*)) (struct Point*) main:::1::point_i - (var) main:::1::$2 ← (var) main:::1::$1 + (byte) OFFS_X - *((var) main:::1::$2) ← (byte) main:::1::i - (var) main:::1::$3 ← ((byte*)) (struct Point*) main:::1::point_i - (var) main:::1::$4 ← (var) main:::1::$3 + (byte) OFFS_Y - (var) main:::1::$5 ← (byte) main:::1::i + (number) 4 - *((var) main:::1::$4) ← (var) main:::1::$5 - (byte) main:::1::i ← (byte) main:::1::i + rangenext(0,3) - (var) main:::1::$6 ← (byte) main:::1::i != rangelast(0,3) - if((var) main:::1::$6) goto main:::1::@1 - (byte*) main::SCREEN ← (number) $400 - (byte) main:::2::i ← (byte) 0 -main:::2::@1: - (var) main:::2::$0 ← (struct Point[4]) points + (byte) main:::2::i - (struct Point*) main:::2::point_i ← (var) main:::2::$0 - (var) main:::2::$1 ← ((byte*)) (struct Point*) main:::2::point_i - (var) main:::2::$2 ← (var) main:::2::$1 + (byte) OFFS_X - *((byte*) main::SCREEN + (byte) main:::2::i) ← *((var) main:::2::$2) - (var) main:::2::$3 ← (byte*) main::SCREEN + (number) $28 - (var) main:::2::$4 ← ((byte*)) (struct Point*) main:::2::point_i - (var) main:::2::$5 ← (var) main:::2::$4 + (byte) OFFS_Y - *((var) main:::2::$3 + (byte) main:::2::i) ← *((var) main:::2::$5) - (byte) main:::2::i ← (byte) main:::2::i + rangenext(0,3) - (var) main:::2::$6 ← (byte) main:::2::i != rangelast(0,3) - if((var) main:::2::$6) goto main:::2::@1 -main::@return: - return -endproc // main() - call main - -SYMBOLS -(label) @1 -(label) @begin -(label) @end -(byte) OFFS_X -(byte) OFFS_Y -(byte) Point::x -(byte) Point::y -(byte) SIZEOF_POINT -(void()) main() -(struct Point*~) main::$0 -(byte*~) main::$1 -(byte*~) main::$10 -(byte*~) main::$11 -(byte*~) main::$12 -(bool~) main::$13 -(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::@4 -(label) main::@return -(byte*) main::SCREEN -(byte) main::i -(byte) main::i1 -(struct Point*) main::point_i -(struct Point*) main::point_i1 -(struct Point[4]) points - 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 -INITIAL CONTROL FLOW GRAPH -@begin: scope:[] from - [0] (struct Point[4]) points ← { fill( 4, 0) } - [1] (byte) SIZEOF_POINT ← (number) 2 - [2] (byte) OFFS_X ← (number) 0 - [3] (byte) OFFS_Y ← (number) 1 - to:@1 -main: scope:[main] from - [4] (byte) main::i ← (byte) 0 - to:main::@1 -main::@1: scope:[main] from main main::@1 - [5] (byte~) main::$14 ← (byte) main::i * (const byte) SIZEOF_STRUCT_POINT - [6] (struct Point*~) main::$0 ← (struct Point[4]) points + (byte~) main::$14 - [7] (struct Point*) main::point_i ← (struct Point*~) main::$0 - [8] (byte*~) main::$1 ← ((byte*)) (struct Point*) main::point_i - [9] (byte*~) main::$2 ← (byte*~) main::$1 + (byte) OFFS_X - [10] *((byte*~) main::$2) ← (byte) main::i - [11] (byte*~) main::$3 ← ((byte*)) (struct Point*) main::point_i - [12] (byte*~) main::$4 ← (byte*~) main::$3 + (byte) OFFS_Y - [13] (number~) main::$5 ← (byte) main::i + (number) 4 - [14] *((byte*~) main::$4) ← (number~) main::$5 - [15] (byte) main::i ← (byte) main::i + rangenext(0,3) - [16] (bool~) main::$6 ← (byte) main::i != rangelast(0,3) - [17] if((bool~) main::$6) goto main::@1 - to:main::@2 -main::@2: scope:[main] from main::@1 - [18] (byte*) main::SCREEN ← ((byte*)) (number) $400 - [19] (byte) main::i1 ← (byte) 0 - to:main::@3 -main::@3: scope:[main] from main::@2 main::@3 - [20] (byte~) main::$15 ← (byte) main::i1 * (const byte) SIZEOF_STRUCT_POINT - [21] (struct Point*~) main::$7 ← (struct Point[4]) points + (byte~) main::$15 - [22] (struct Point*) main::point_i1 ← (struct Point*~) main::$7 - [23] (byte*~) main::$8 ← ((byte*)) (struct Point*) main::point_i1 - [24] (byte*~) main::$9 ← (byte*~) main::$8 + (byte) OFFS_X - [25] *((byte*) main::SCREEN + (byte) main::i1) ← *((byte*~) main::$9) - [26] (byte*~) main::$10 ← (byte*) main::SCREEN + (number) $28 - [27] (byte*~) main::$11 ← ((byte*)) (struct Point*) main::point_i1 - [28] (byte*~) main::$12 ← (byte*~) main::$11 + (byte) OFFS_Y - [29] *((byte*~) main::$10 + (byte) main::i1) ← *((byte*~) main::$12) - [30] (byte) main::i1 ← (byte) main::i1 + rangenext(0,3) - [31] (bool~) main::$13 ← (byte) main::i1 != rangelast(0,3) - [32] if((bool~) main::$13) goto main::@3 - to:main::@4 -main::@4: scope:[main] from main::@3 - to:main::@return -main::@return: scope:[main] from main::@4 - [33] return - to:@return -@1: scope:[] from @begin - [34] call main - to:@end -@end: scope:[] from @1 - -Eliminating unused variable (byte) SIZEOF_POINT and assignment [1] (byte) SIZEOF_POINT ← (number) 2 Culled Empty Block (label) main::@4 -PROCEDURE MODIFY VARIABLE ANALYSIS - -Completing Phi functions... CONTROL FLOW GRAPH SSA @begin: scope:[] from