diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index 592295b90..44dfece28 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -78,40 +78,33 @@ public class Compiler { Pass1GenerateControlFlowGraph pass1GenerateControlFlowGraph = new Pass1GenerateControlFlowGraph(programScope); ControlFlowGraph controlFlowGraph = pass1GenerateControlFlowGraph.generate(statementSequence); - program.setGraph(controlFlowGraph); - new Pass1AddTypePromotions(program).addPromotions(); + new Pass1AddTypePromotions(program).execute(); log.append("INITIAL CONTROL FLOW GRAPH"); log.append(program.getGraph().toString(program)); - new Pass1ExtractInlineStrings(program).extract(); - new Pass1EliminateUncalledProcedures(program).eliminate(); - new Pass1EliminateEmptyBlocks(program).eliminate(); + new Pass1ExtractInlineStrings(program).execute(); + new Pass1EliminateUncalledProcedures(program).execute(); + new Pass1EliminateEmptyBlocks(program).execute(); log.append("CONTROL FLOW GRAPH"); log.append(program.getGraph().toString(program)); - new Pass1ModifiedVarsAnalysis(program).findModifiedVars(); + new Pass1ModifiedVarsAnalysis(program).execute(); log.append("PROCEDURE MODIFY VARIABLE ANALYSIS"); log.append(program.getProcedureModifiedVars().toString(program)); - Pass1ProcedureCallParameters pass1ProcedureCallParameters = - new Pass1ProcedureCallParameters(program); - pass1ProcedureCallParameters.generate(); + new Pass1ProcedureCallParameters(program).generate(); log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL"); log.append(program.getGraph().toString(program)); - Pass1GenerateSingleStaticAssignmentForm pass1GenerateSingleStaticAssignmentForm = - new Pass1GenerateSingleStaticAssignmentForm(log, program); - pass1GenerateSingleStaticAssignmentForm.generate(); + new Pass1GenerateSingleStaticAssignmentForm(program).execute(); log.append("CONTROL FLOW GRAPH SSA"); log.append(program.getGraph().toString(program)); - Pass1ProcedureCallsReturnValue pass1ProcedureCallsReturnValue = - new Pass1ProcedureCallsReturnValue(program); - program.setGraph(pass1ProcedureCallsReturnValue.generate()); + program.setGraph(new Pass1ProcedureCallsReturnValue(program).generate()); log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN"); log.append(program.getGraph().toString(program)); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1AddTypePromotions.java b/src/main/java/dk/camelot64/kickc/passes/Pass1AddTypePromotions.java index 8e88e4749..df71a16dc 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1AddTypePromotions.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1AddTypePromotions.java @@ -8,23 +8,15 @@ import java.util.ListIterator; /** * Add casts in all assignments where types are not equal, but the rValue type can be promoted to the lValue type. */ -public class Pass1AddTypePromotions { - - private Program program; +public class Pass1AddTypePromotions extends Pass1Base { public Pass1AddTypePromotions(Program program) { - this.program = program; + super(program); } - public Program getProgram() { - return program; - } - public ProgramScope getSymbols() { - return program.getScope(); - } - - public void addPromotions() { + @Override + public boolean executeStep() { for (ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) { List statements = block.getStatements(); ListIterator stmtIt = statements.listIterator(); @@ -36,7 +28,7 @@ public class Pass1AddTypePromotions { // TODO: Implement promotion for calls } } - + return false; } /** @@ -50,8 +42,8 @@ public class Pass1AddTypePromotions { */ private void getPromotionAssignment(StatementAssignment assignment, ListIterator stmtIt) { LValue lValue = assignment.getlValue(); - SymbolType lValueType = SymbolTypeInference.inferType(getSymbols(), lValue); - SymbolType rValueType = SymbolTypeInference.inferTypeRValue(getSymbols(), assignment); + SymbolType lValueType = SymbolTypeInference.inferType(getScope(), lValue); + SymbolType rValueType = SymbolTypeInference.inferTypeRValue(getScope(), assignment); if (SymbolTypeInference.typeMatch(lValueType, rValueType)) { return; } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1Base.java b/src/main/java/dk/camelot64/kickc/passes/Pass1Base.java new file mode 100644 index 000000000..3d01255e4 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1Base.java @@ -0,0 +1,54 @@ +package dk.camelot64.kickc.passes; + +import dk.camelot64.kickc.CompileLog; +import dk.camelot64.kickc.model.*; + +import java.util.List; +import java.util.ListIterator; + +/** + * Pass 1 (before SSA optimizations) base class + */ +public abstract class Pass1Base { + + private Program program; + + public Pass1Base(Program program) { + this.program = program; + } + + /** + * Execute the pass 1 step repeatedly until it is done. + */ + public void execute() { + boolean again = true; + while (again) { + again = executeStep(); + } + } + + /** + * Execute the pass 1 step. + * + * @return boolean indicating whether the step should be repeated. + */ + abstract boolean executeStep(); + + public Program getProgram() { + return program; + } + + public ProgramScope getScope() { + return program.getScope(); + } + + public CompileLog getLog() { + return program.getLog(); + } + + public ControlFlowGraph getGraph() { + return program.getGraph(); + } + + +} diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1EliminateEmptyBlocks.java b/src/main/java/dk/camelot64/kickc/passes/Pass1EliminateEmptyBlocks.java index f5dadf1a5..ca124fd05 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1EliminateEmptyBlocks.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1EliminateEmptyBlocks.java @@ -10,17 +10,16 @@ import java.util.List; /** * Eliminate empty blocks in pass 1 (before creating SSA) */ -public class Pass1EliminateEmptyBlocks { - - private Program program; +public class Pass1EliminateEmptyBlocks extends Pass1Base { public Pass1EliminateEmptyBlocks(Program program) { - this.program = program; + super(program); } - public boolean eliminate() { - CompileLog log = program.getLog(); - ControlFlowGraph graph = program.getGraph(); + @Override + boolean executeStep() { + CompileLog log = getLog(); + ControlFlowGraph graph = getProgram().getGraph(); Collection blocks = graph.getAllBlocks(); List removeList = new ArrayList<>(); for (ControlFlowBlock block : blocks) { @@ -44,16 +43,18 @@ public class Pass1EliminateEmptyBlocks { } } } + boolean modified = false; for (LabelRef labelRef : removeList) { - Symbol removeSymbol = program.getScope().getSymbol(labelRef); + Symbol removeSymbol = getScope().getSymbol(labelRef); if(removeSymbol instanceof Label) { Label label = (Label) removeSymbol; graph.remove(labelRef); label.getScope().remove(label); log.append("Removing empty block "+labelRef); + modified = true; } } - return removeList.size()>0; + return modified; } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1EliminateUncalledProcedures.java b/src/main/java/dk/camelot64/kickc/passes/Pass1EliminateUncalledProcedures.java index 8e1c00588..75420e2da 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1EliminateUncalledProcedures.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1EliminateUncalledProcedures.java @@ -8,17 +8,16 @@ import java.util.List; import java.util.Set; /** Eliminate uncalled methods */ -public class Pass1EliminateUncalledProcedures { - - private Program program; +public class Pass1EliminateUncalledProcedures extends Pass1Base { public Pass1EliminateUncalledProcedures(Program program) { - this.program = program; + super(program); } - public void eliminate() { + @Override + boolean executeStep() { Set calledProcedures = new LinkedHashSet<>(); - for (ControlFlowBlock block : program.getGraph().getAllBlocks()) { + for (ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) { for (Statement statement : block.getStatements()) { if(statement instanceof StatementCall) { StatementCall call = (StatementCall) statement; @@ -29,7 +28,7 @@ public class Pass1EliminateUncalledProcedures { } Set unusedProcedures = new LinkedHashSet<>(); - Collection allProcedures = program.getScope().getAllProcedures(true); + Collection allProcedures = getProgram().getScope().getAllProcedures(true); for (Procedure procedure : allProcedures) { if(!calledProcedures.contains(procedure.getRef())) { // The procedure is not used - mark for removal! @@ -38,16 +37,16 @@ public class Pass1EliminateUncalledProcedures { } for (ProcedureRef unusedProcedure : unusedProcedures) { - program.getLog().append("Removing unused procedure "+unusedProcedure); - Procedure procedure = program.getScope().getProcedure(unusedProcedure); - List procedureBlocks = program.getGraph().getScopeBlocks(unusedProcedure); + getLog().append("Removing unused procedure "+unusedProcedure); + Procedure procedure = getProgram().getScope().getProcedure(unusedProcedure); + List procedureBlocks = getProgram().getGraph().getScopeBlocks(unusedProcedure); for (ControlFlowBlock procedureBlock : procedureBlocks) { - program.getGraph().remove(procedureBlock.getLabel()); + getProgram().getGraph().remove(procedureBlock.getLabel()); } procedure.getScope().remove(procedure); } - + return false; } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1ExtractInlineStrings.java b/src/main/java/dk/camelot64/kickc/passes/Pass1ExtractInlineStrings.java index 0a462d7a5..6c4acc4da 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1ExtractInlineStrings.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1ExtractInlineStrings.java @@ -7,18 +7,17 @@ import java.util.*; /** * Eliminate uncalled methods */ -public class Pass1ExtractInlineStrings { - - private Program program; +public class Pass1ExtractInlineStrings extends Pass1Base { public Pass1ExtractInlineStrings(Program program) { - this.program = program; + super(program); } - public void extract() { - for (ControlFlowBlock block : program.getGraph().getAllBlocks()) { + @Override + boolean executeStep() { + for (ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) { ListIterator stmtIt = block.getStatements().listIterator(); - Scope blockScope = program.getScope().getScope(block.getScope()); + Scope blockScope = getProgram().getScope().getScope(block.getScope()); while (stmtIt.hasNext()) { Statement statement = stmtIt.next(); if (statement instanceof StatementCall) { @@ -28,7 +27,7 @@ public class Pass1ExtractInlineStrings { while (parIt.hasNext()) { RValue parameter = parIt.next(); if (parameter instanceof ConstantString) { - Procedure procedure = program.getScope().getProcedure(call.getProcedure()); + Procedure procedure = getProgram().getScope().getProcedure(call.getProcedure()); String parameterName = procedure.getParameterNames().get(parNum); ConstantVar strConst = createStringConstantVar(blockScope, (ConstantString) parameter, parameterName); parIt.set(strConst.getRef()); @@ -57,7 +56,7 @@ public class Pass1ExtractInlineStrings { } } } - + return false; } private ConstantVar createStringConstantVar(Scope blockScope, ConstantString constantString, String nameHint) { @@ -73,7 +72,7 @@ public class Pass1ExtractInlineStrings { } ConstantVar strConst = new ConstantVar(name, blockScope, new SymbolTypeArray(SymbolType.BYTE), constantString); blockScope.add(strConst); - program.getLog().append("Creating constant string variable for inline " + strConst.toString(program) + " \"" + constantString.getValue() + "\""); + getLog().append("Creating constant string variable for inline " + strConst.toString(getProgram()) + " \"" + constantString.getValue() + "\""); return strConst; } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java b/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java index e7c8949b9..b9aee227a 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java @@ -1,6 +1,5 @@ package dk.camelot64.kickc.passes; -import dk.camelot64.kickc.CompileLog; import dk.camelot64.kickc.model.*; import java.util.LinkedHashMap; @@ -11,41 +10,37 @@ import java.util.Map; *

First versions all variable assignments, then versions all variable usages and introduces necessary Phi-functions, *

See https://en.wikipedia.org/wiki/Static_single_assignment_form */ -public class Pass1GenerateSingleStaticAssignmentForm { +public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base { - private CompileLog log; - private ProgramScope symbols; - private ControlFlowGraph controlFlowGraph; - - public Pass1GenerateSingleStaticAssignmentForm(CompileLog log, Program program) { - this.log = log; - this.symbols = program.getScope(); - this.controlFlowGraph = program.getGraph(); + public Pass1GenerateSingleStaticAssignmentForm(Program program) { + super(program); } - public void generate() { + @Override + boolean executeStep() { versionAllAssignments(); versionAllUses(); boolean done; do { - log.append("Completing Phi functions..."); + getLog().append("Completing Phi functions..."); done = completePhiFunctions(); //log.append(this.controlFlowGraph.toString(symbols)); } while (!done); + return false; } /** * Version all non-versioned non-intermediary being assigned a value. */ private void versionAllAssignments() { - for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) { + for (ControlFlowBlock block : getGraph().getAllBlocks()) { for (Statement statement : block.getStatements()) { if (statement instanceof StatementLValue) { StatementLValue statementLValue = (StatementLValue) statement; LValue lValue = statementLValue.getlValue(); if (lValue instanceof VariableRef) { VariableRef lValueRef = (VariableRef) lValue; - Variable assignedVar = symbols.getVariable(lValueRef); + Variable assignedVar = getScope().getVariable(lValueRef); if (assignedVar instanceof VariableUnversioned) { // Assignment to a non-versioned non-intermediary variable VariableUnversioned assignedSymbol = (VariableUnversioned) assignedVar; @@ -62,7 +57,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { * Version all uses of non-versioned non-intermediary variables */ private void versionAllUses() { - for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) { + for (ControlFlowBlock block : getGraph().getAllBlocks()) { // Newest version of variables in the block. Map blockVersions = new LinkedHashMap<>(); // New phi functions introduced in the block to create versions of variables. @@ -116,7 +111,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { LValue lValue = assignment.getlValue(); if (lValue instanceof VariableRef) { VariableRef lValueRef = (VariableRef) lValue; - Variable variable = symbols.getVariable(lValueRef); + Variable variable = getScope().getVariable(lValueRef); if (variable instanceof VariableVersion) { VariableVersion versioned = (VariableVersion) variable; blockVersions.put(versioned.getVersionOf(), versioned); @@ -165,7 +160,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { Map blockNewPhis) { VariableVersion version = null; if (rValue instanceof VariableRef) { - Variable rValueVar = symbols.getVariable((VariableRef) rValue); + Variable rValueVar = getScope().getVariable((VariableRef) rValue); if (rValueVar instanceof VariableUnversioned) { // rValue needs versioning - look for version in statements VariableUnversioned rSymbol = (VariableUnversioned) rValueVar; @@ -193,7 +188,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { private boolean completePhiFunctions() { Map> newPhis = new LinkedHashMap<>(); Map> symbolMap = buildSymbolMap(); - for (ControlFlowBlock block : this.controlFlowGraph.getAllBlocks()) { + for (ControlFlowBlock block : getGraph().getAllBlocks()) { for (Statement statement : block.getStatements()) { if (statement instanceof StatementPhiBlock) { @@ -201,9 +196,9 @@ public class Pass1GenerateSingleStaticAssignmentForm { for (StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) { if (phiVariable.isEmpty()) { VariableRef phiLValVarRef = phiVariable.getVariable(); - VariableVersion versioned = (VariableVersion) symbols.getVariable(phiLValVarRef); + VariableVersion versioned = (VariableVersion) getScope().getVariable(phiLValVarRef); VariableUnversioned unversioned = versioned.getVersionOf(); - for (ControlFlowBlock predecessor : controlFlowGraph.getPredecessors(block)) { + for (ControlFlowBlock predecessor : getGraph().getPredecessors(block)) { LabelRef predecessorLabel = predecessor.getLabel(); Map predecessorMap = symbolMap.get(predecessorLabel); VariableVersion previousSymbol = null; @@ -232,7 +227,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { } } // Ads new phi functions to blocks - for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) { + for (ControlFlowBlock block : getGraph().getAllBlocks()) { Map blockNewPhis = newPhis.get(block.getLabel()); if (blockNewPhis != null) { for (VariableUnversioned symbol : blockNewPhis.keySet()) { @@ -250,7 +245,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { */ private Map> buildSymbolMap() { Map> symbolMap = new LinkedHashMap<>(); - for (ControlFlowBlock block : this.controlFlowGraph.getAllBlocks()) { + for (ControlFlowBlock block : getGraph().getAllBlocks()) { for (Statement statement : block.getStatements()) { if (statement instanceof StatementLValue) { StatementLValue assignment = (StatementLValue) statement; @@ -268,7 +263,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { private void addSymbolToMap(Map> symbolMap, ControlFlowBlock block, LValue lValue) { if (lValue instanceof VariableRef) { - Variable lValueVar = symbols.getVariable((VariableRef) lValue); + Variable lValueVar = getScope().getVariable((VariableRef) lValue); if (lValueVar instanceof VariableVersion) { VariableVersion versioned = (VariableVersion) lValueVar; LabelRef label = block.getLabel(); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1ModifiedVarsAnalysis.java b/src/main/java/dk/camelot64/kickc/passes/Pass1ModifiedVarsAnalysis.java index 0f72c343a..42db39e54 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1ModifiedVarsAnalysis.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1ModifiedVarsAnalysis.java @@ -5,22 +5,22 @@ import dk.camelot64.kickc.model.*; import java.util.*; /** Find all variables from an outer scope modified in an inner scope (ie. a procedure) */ -public class Pass1ModifiedVarsAnalysis { - - private Program program; +public class Pass1ModifiedVarsAnalysis extends Pass1Base { public Pass1ModifiedVarsAnalysis(Program program) { - this.program = program; + super(program); } - public void findModifiedVars() { + @Override + boolean executeStep() { Map> modified = new LinkedHashMap<>(); - Collection allProcedures = program.getScope().getAllProcedures(true); + Collection allProcedures = getScope().getAllProcedures(true); for (Procedure procedure : allProcedures) { Set modifiedVars = getModifiedVars(procedure); modified.put(procedure.getRef(), modifiedVars); } - program.setProcedureModifiedVars(new ProcedureModifiedVars(modified)); + getProgram().setProcedureModifiedVars(new ProcedureModifiedVars(modified)); + return false; } /** Get all outside variables modified by a procedure (or any sub-procedure called by the procedure). @@ -31,7 +31,7 @@ public class Pass1ModifiedVarsAnalysis { public Set getModifiedVars(Procedure procedure) { Set modified = new LinkedHashSet<>(); ScopeRef procScope = procedure.getRef(); - List procBlocks = program.getGraph().getScopeBlocks(procScope); + List procBlocks = getProgram().getGraph().getScopeBlocks(procScope); for (ControlFlowBlock block : procBlocks) { for (Statement statement : block.getStatements()) { if(statement instanceof StatementLValue) { @@ -44,7 +44,7 @@ public class Pass1ModifiedVarsAnalysis { } if(statement instanceof StatementCall) { ProcedureRef called = ((StatementCall) statement).getProcedure(); - Procedure calledProc = program.getScope().getProcedure(called); + Procedure calledProc = getScope().getProcedure(called); modified.addAll(getModifiedVars(calledProc)); } } diff --git a/src/main/java/dk/camelot64/kickc/test/TestPrograms.java b/src/main/java/dk/camelot64/kickc/test/TestPrograms.java index 6844d2281..f9208a33b 100644 --- a/src/main/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/main/java/dk/camelot64/kickc/test/TestPrograms.java @@ -24,6 +24,14 @@ public class TestPrograms extends TestCase { helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/"); } + public void testUnusedVars() throws IOException, URISyntaxException { + compileAndCompare("unused-vars"); + } + + public void testFillscreen() throws IOException, URISyntaxException { + compileAndCompare("fillscreen"); + } + public void testLiverangeCallProblem() throws IOException, URISyntaxException { compileAndCompare("liverange-call-problem"); } diff --git a/src/main/java/dk/camelot64/kickc/test/fillscreen.kc b/src/main/java/dk/camelot64/kickc/test/fillscreen.kc new file mode 100644 index 000000000..12b545991 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/fillscreen.kc @@ -0,0 +1,19 @@ +byte *SCREEN = $0400; + +void main() { + byte c = (*SCREEN); + fillscreen(c); +} + +void fillscreen(byte c) { + for(byte j : 0..255) { + byte* SCREEN2 = SCREEN+$100; + byte* SCREEN3 = SCREEN+$200; + byte* SCREEN4 = SCREEN+$3e8; + SCREEN[j] = c; + SCREEN2[j] = c; + SCREEN3[j] = c; + SCREEN4[j] = c; + } +} + diff --git a/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.asm b/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.asm new file mode 100644 index 000000000..73fb6ffba --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.asm @@ -0,0 +1,25 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const SCREEN = $400 + jsr main +main: { + lda SCREEN + jsr fillscreen + rts +} +fillscreen: { + .const SCREEN2 = SCREEN+$100 + .const SCREEN3 = SCREEN+$200 + .const SCREEN4 = SCREEN+$3e8 + ldx #0 + b1: + sta SCREEN,x + sta SCREEN2,x + sta SCREEN3,x + sta SCREEN4,x + inx + cpx #0 + bne b1 + rts +} diff --git a/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.cfg b/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.cfg new file mode 100644 index 000000000..28b29723c --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.cfg @@ -0,0 +1,32 @@ +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@2 +@2: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @2 + [3] phi() [ ] ( ) +main: scope:[main] from @2 + [4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] ( main:2 [ main::c#0 ] ) + [5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] ( main:2 [ fillscreen::c#0 ] ) + [6] call fillscreen param-assignment [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main + [7] return [ ] ( main:2 [ ] ) + to:@return +fillscreen: scope:[fillscreen] from main + [8] phi() [ fillscreen::c#0 ] ( main:2::fillscreen:6 [ fillscreen::c#0 ] ) + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + [9] (byte) fillscreen::j#2 ← phi( fillscreen/(byte/signed byte/word/signed word) 0 fillscreen::@1/(byte) fillscreen::j#1 ) [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) + [10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) + [11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) + [12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) + [13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) + [14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) + [15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + [16] return [ ] ( main:2::fillscreen:6 [ ] ) + to:@return diff --git a/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.log b/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.log new file mode 100644 index 000000000..c57277a94 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.log @@ -0,0 +1,1356 @@ +byte *SCREEN = $0400; + +void main() { + byte c = (*SCREEN); + fillscreen(c); +} + +void fillscreen(byte c) { + for(byte j : 0..255) { + byte* SCREEN2 = SCREEN+$100; + byte* SCREEN3 = SCREEN+$200; + byte* SCREEN4 = SCREEN+$3e8; + SCREEN[j] = c; + SCREEN2[j] = c; + SCREEN3[j] = c; + SCREEN4[j] = c; + } +} + + +PROGRAM + (byte*) SCREEN ← (word/signed word) 1024 +proc (void()) main() + (byte) main::c ← *((byte*) SCREEN) + (void~) main::$0 ← call fillscreen (byte) main::c +main::@return: + return +endproc // main() +proc (void()) fillscreen((byte) fillscreen::c) + (byte) fillscreen::j ← (byte/signed byte/word/signed word) 0 +fillscreen::@1: + (byte*~) fillscreen::$0 ← (byte*) SCREEN + (word/signed word) 256 + (byte*) fillscreen::SCREEN2 ← (byte*~) fillscreen::$0 + (byte*~) fillscreen::$1 ← (byte*) SCREEN + (word/signed word) 512 + (byte*) fillscreen::SCREEN3 ← (byte*~) fillscreen::$1 + (byte*~) fillscreen::$2 ← (byte*) SCREEN + (word/signed word) 1000 + (byte*) fillscreen::SCREEN4 ← (byte*~) fillscreen::$2 + *((byte*) SCREEN + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN2 + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN3 + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN4 + (byte) fillscreen::j) ← (byte) fillscreen::c + (byte) fillscreen::j ← ++ (byte) fillscreen::j + (boolean~) fillscreen::$3 ← (byte) fillscreen::j != (byte/signed byte/word/signed word) 0 + if((boolean~) fillscreen::$3) goto fillscreen::@1 +fillscreen::@return: + return +endproc // fillscreen() + call main + +SYMBOLS +(byte*) SCREEN +(void()) fillscreen((byte) fillscreen::c) +(byte*~) fillscreen::$0 +(byte*~) fillscreen::$1 +(byte*~) fillscreen::$2 +(boolean~) fillscreen::$3 +(label) fillscreen::@1 +(label) fillscreen::@return +(byte*) fillscreen::SCREEN2 +(byte*) fillscreen::SCREEN3 +(byte*) fillscreen::SCREEN4 +(byte) fillscreen::c +(byte) fillscreen::j +(void()) main() +(void~) main::$0 +(label) main::@return +(byte) main::c + +Promoting word/signed word to byte* in SCREEN ← ((byte*)) 1024 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN ← ((byte*)) (word/signed word) 1024 + to:@1 +main: scope:[main] from + (byte) main::c ← *((byte*) SCREEN) + (void~) main::$0 ← call fillscreen (byte) main::c + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + to:@2 +fillscreen: scope:[fillscreen] from + (byte) fillscreen::j ← (byte/signed byte/word/signed word) 0 + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte*~) fillscreen::$0 ← (byte*) SCREEN + (word/signed word) 256 + (byte*) fillscreen::SCREEN2 ← (byte*~) fillscreen::$0 + (byte*~) fillscreen::$1 ← (byte*) SCREEN + (word/signed word) 512 + (byte*) fillscreen::SCREEN3 ← (byte*~) fillscreen::$1 + (byte*~) fillscreen::$2 ← (byte*) SCREEN + (word/signed word) 1000 + (byte*) fillscreen::SCREEN4 ← (byte*~) fillscreen::$2 + *((byte*) SCREEN + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN2 + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN3 + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN4 + (byte) fillscreen::j) ← (byte) fillscreen::c + (byte) fillscreen::j ← ++ (byte) fillscreen::j + (boolean~) fillscreen::$3 ← (byte) fillscreen::j != (byte/signed byte/word/signed word) 0 + if((boolean~) fillscreen::$3) goto fillscreen::@1 + to:fillscreen::@2 +fillscreen::@2: scope:[fillscreen] from fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@2 + return + to:@return +@2: scope:[] from @1 + call main + to:@end +@end: scope:[] from @2 + +Removing empty block @1 +Removing empty block fillscreen::@2 +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN ← ((byte*)) (word/signed word) 1024 + to:@2 +main: scope:[main] from + (byte) main::c ← *((byte*) SCREEN) + (void~) main::$0 ← call fillscreen (byte) main::c + to:main::@return +main::@return: scope:[main] from main + return + to:@return +fillscreen: scope:[fillscreen] from + (byte) fillscreen::j ← (byte/signed byte/word/signed word) 0 + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte*~) fillscreen::$0 ← (byte*) SCREEN + (word/signed word) 256 + (byte*) fillscreen::SCREEN2 ← (byte*~) fillscreen::$0 + (byte*~) fillscreen::$1 ← (byte*) SCREEN + (word/signed word) 512 + (byte*) fillscreen::SCREEN3 ← (byte*~) fillscreen::$1 + (byte*~) fillscreen::$2 ← (byte*) SCREEN + (word/signed word) 1000 + (byte*) fillscreen::SCREEN4 ← (byte*~) fillscreen::$2 + *((byte*) SCREEN + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN2 + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN3 + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN4 + (byte) fillscreen::j) ← (byte) fillscreen::c + (byte) fillscreen::j ← ++ (byte) fillscreen::j + (boolean~) fillscreen::$3 ← (byte) fillscreen::j != (byte/signed byte/word/signed word) 0 + if((boolean~) fillscreen::$3) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + call main + to:@end +@end: scope:[] from @2 + +PROCEDURE MODIFY VARIABLE ANALYSIS + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL +@begin: scope:[] from + (byte*) SCREEN ← ((byte*)) (word/signed word) 1024 + to:@2 +main: scope:[main] from @2 + (byte) main::c ← *((byte*) SCREEN) + (byte) fillscreen::c ← (byte) main::c + call fillscreen param-assignment + to:main::@1 +main::@1: scope:[main] from main + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +fillscreen: scope:[fillscreen] from main + (byte) fillscreen::j ← (byte/signed byte/word/signed word) 0 + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte*~) fillscreen::$0 ← (byte*) SCREEN + (word/signed word) 256 + (byte*) fillscreen::SCREEN2 ← (byte*~) fillscreen::$0 + (byte*~) fillscreen::$1 ← (byte*) SCREEN + (word/signed word) 512 + (byte*) fillscreen::SCREEN3 ← (byte*~) fillscreen::$1 + (byte*~) fillscreen::$2 ← (byte*) SCREEN + (word/signed word) 1000 + (byte*) fillscreen::SCREEN4 ← (byte*~) fillscreen::$2 + *((byte*) SCREEN + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN2 + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN3 + (byte) fillscreen::j) ← (byte) fillscreen::c + *((byte*) fillscreen::SCREEN4 + (byte) fillscreen::j) ← (byte) fillscreen::c + (byte) fillscreen::j ← ++ (byte) fillscreen::j + (boolean~) fillscreen::$3 ← (byte) fillscreen::j != (byte/signed byte/word/signed word) 0 + if((boolean~) fillscreen::$3) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + call main param-assignment + to:@3 +@3: scope:[] from @2 + to:@end +@end: scope:[] from @3 + +Completing Phi functions... +Completing Phi functions... +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) SCREEN#0 ← ((byte*)) (word/signed word) 1024 + to:@2 +main: scope:[main] from @2 + (byte*) SCREEN#1 ← phi( @2/(byte*) SCREEN#3 ) + (byte) main::c#0 ← *((byte*) SCREEN#1) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@1 +main::@1: scope:[main] from main + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +fillscreen: scope:[fillscreen] from main + (byte) fillscreen::c#2 ← phi( main/(byte) fillscreen::c#0 ) + (byte*) SCREEN#4 ← phi( main/(byte*) SCREEN#1 ) + (byte) fillscreen::j#0 ← (byte/signed byte/word/signed word) 0 + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte) fillscreen::j#2 ← phi( fillscreen/(byte) fillscreen::j#0 fillscreen::@1/(byte) fillscreen::j#1 ) + (byte) fillscreen::c#1 ← phi( fillscreen/(byte) fillscreen::c#2 fillscreen::@1/(byte) fillscreen::c#1 ) + (byte*) SCREEN#2 ← phi( fillscreen/(byte*) SCREEN#4 fillscreen::@1/(byte*) SCREEN#2 ) + (byte*~) fillscreen::$0 ← (byte*) SCREEN#2 + (word/signed word) 256 + (byte*) fillscreen::SCREEN2#0 ← (byte*~) fillscreen::$0 + (byte*~) fillscreen::$1 ← (byte*) SCREEN#2 + (word/signed word) 512 + (byte*) fillscreen::SCREEN3#0 ← (byte*~) fillscreen::$1 + (byte*~) fillscreen::$2 ← (byte*) SCREEN#2 + (word/signed word) 1000 + (byte*) fillscreen::SCREEN4#0 ← (byte*~) fillscreen::$2 + *((byte*) SCREEN#2 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + (boolean~) fillscreen::$3 ← (byte) fillscreen::j#1 != (byte/signed byte/word/signed word) 0 + if((boolean~) fillscreen::$3) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + (byte*) SCREEN#3 ← phi( @begin/(byte*) SCREEN#0 ) + call main param-assignment + to:@3 +@3: scope:[] from @2 + to:@end +@end: scope:[] from @3 + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + (byte*) SCREEN#0 ← ((byte*)) (word/signed word) 1024 + to:@2 +main: scope:[main] from @2 + (byte*) SCREEN#1 ← phi( @2/(byte*) SCREEN#3 ) + (byte) main::c#0 ← *((byte*) SCREEN#1) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@1 +main::@1: scope:[main] from main + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +fillscreen: scope:[fillscreen] from main + (byte) fillscreen::c#2 ← phi( main/(byte) fillscreen::c#0 ) + (byte*) SCREEN#4 ← phi( main/(byte*) SCREEN#1 ) + (byte) fillscreen::j#0 ← (byte/signed byte/word/signed word) 0 + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte) fillscreen::j#2 ← phi( fillscreen/(byte) fillscreen::j#0 fillscreen::@1/(byte) fillscreen::j#1 ) + (byte) fillscreen::c#1 ← phi( fillscreen/(byte) fillscreen::c#2 fillscreen::@1/(byte) fillscreen::c#1 ) + (byte*) SCREEN#2 ← phi( fillscreen/(byte*) SCREEN#4 fillscreen::@1/(byte*) SCREEN#2 ) + (byte*~) fillscreen::$0 ← (byte*) SCREEN#2 + (word/signed word) 256 + (byte*) fillscreen::SCREEN2#0 ← (byte*~) fillscreen::$0 + (byte*~) fillscreen::$1 ← (byte*) SCREEN#2 + (word/signed word) 512 + (byte*) fillscreen::SCREEN3#0 ← (byte*~) fillscreen::$1 + (byte*~) fillscreen::$2 ← (byte*) SCREEN#2 + (word/signed word) 1000 + (byte*) fillscreen::SCREEN4#0 ← (byte*~) fillscreen::$2 + *((byte*) SCREEN#2 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + (boolean~) fillscreen::$3 ← (byte) fillscreen::j#1 != (byte/signed byte/word/signed word) 0 + if((boolean~) fillscreen::$3) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + (byte*) SCREEN#3 ← phi( @begin/(byte*) SCREEN#0 ) + call main param-assignment + to:@3 +@3: scope:[] from @2 + to:@end +@end: scope:[] from @3 + +INITIAL SSA SYMBOL TABLE +(label) @2 +(label) @3 +(label) @begin +(label) @end +(byte*) SCREEN +(byte*) SCREEN#0 +(byte*) SCREEN#1 +(byte*) SCREEN#2 +(byte*) SCREEN#3 +(byte*) SCREEN#4 +(void()) fillscreen((byte) fillscreen::c) +(byte*~) fillscreen::$0 +(byte*~) fillscreen::$1 +(byte*~) fillscreen::$2 +(boolean~) fillscreen::$3 +(label) fillscreen::@1 +(label) fillscreen::@return +(byte*) fillscreen::SCREEN2 +(byte*) fillscreen::SCREEN2#0 +(byte*) fillscreen::SCREEN3 +(byte*) fillscreen::SCREEN3#0 +(byte*) fillscreen::SCREEN4 +(byte*) fillscreen::SCREEN4#0 +(byte) fillscreen::c +(byte) fillscreen::c#0 +(byte) fillscreen::c#1 +(byte) fillscreen::c#2 +(byte) fillscreen::j +(byte) fillscreen::j#0 +(byte) fillscreen::j#1 +(byte) fillscreen::j#2 +(void()) main() +(label) main::@1 +(label) main::@return +(byte) main::c +(byte) main::c#0 + +Culled Empty Block (label) main::@1 +Culled Empty Block (label) @3 +Succesful SSA optimization Pass2CullEmptyBlocks +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← ((byte*)) (word/signed word) 1024 + to:@2 +main: scope:[main] from @2 + (byte*) SCREEN#1 ← phi( @2/(byte*) SCREEN#3 ) + (byte) main::c#0 ← *((byte*) SCREEN#1) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@return +main::@return: scope:[main] from main + return + to:@return +fillscreen: scope:[fillscreen] from main + (byte) fillscreen::c#2 ← phi( main/(byte) fillscreen::c#0 ) + (byte*) SCREEN#4 ← phi( main/(byte*) SCREEN#1 ) + (byte) fillscreen::j#0 ← (byte/signed byte/word/signed word) 0 + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte) fillscreen::j#2 ← phi( fillscreen/(byte) fillscreen::j#0 fillscreen::@1/(byte) fillscreen::j#1 ) + (byte) fillscreen::c#1 ← phi( fillscreen/(byte) fillscreen::c#2 fillscreen::@1/(byte) fillscreen::c#1 ) + (byte*) SCREEN#2 ← phi( fillscreen/(byte*) SCREEN#4 fillscreen::@1/(byte*) SCREEN#2 ) + (byte*~) fillscreen::$0 ← (byte*) SCREEN#2 + (word/signed word) 256 + (byte*) fillscreen::SCREEN2#0 ← (byte*~) fillscreen::$0 + (byte*~) fillscreen::$1 ← (byte*) SCREEN#2 + (word/signed word) 512 + (byte*) fillscreen::SCREEN3#0 ← (byte*~) fillscreen::$1 + (byte*~) fillscreen::$2 ← (byte*) SCREEN#2 + (word/signed word) 1000 + (byte*) fillscreen::SCREEN4#0 ← (byte*~) fillscreen::$2 + *((byte*) SCREEN#2 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + (boolean~) fillscreen::$3 ← (byte) fillscreen::j#1 != (byte/signed byte/word/signed word) 0 + if((boolean~) fillscreen::$3) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + (byte*) SCREEN#3 ← phi( @begin/(byte*) SCREEN#0 ) + call main param-assignment + to:@end +@end: scope:[] from @2 + +Not aliassing across scopes: SCREEN#1 SCREEN#3 +Not aliassing across scopes: fillscreen::c#0 main::c#0 +Not aliassing across scopes: SCREEN#4 SCREEN#1 +Not aliassing across scopes: fillscreen::c#2 fillscreen::c#0 +Alias (byte*) fillscreen::SCREEN2#0 = (byte*~) fillscreen::$0 +Alias (byte*) fillscreen::SCREEN3#0 = (byte*~) fillscreen::$1 +Alias (byte*) fillscreen::SCREEN4#0 = (byte*~) fillscreen::$2 +Alias (byte*) SCREEN#0 = (byte*) SCREEN#3 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← ((byte*)) (word/signed word) 1024 + to:@2 +main: scope:[main] from @2 + (byte*) SCREEN#1 ← phi( @2/(byte*) SCREEN#0 ) + (byte) main::c#0 ← *((byte*) SCREEN#1) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@return +main::@return: scope:[main] from main + return + to:@return +fillscreen: scope:[fillscreen] from main + (byte) fillscreen::c#2 ← phi( main/(byte) fillscreen::c#0 ) + (byte*) SCREEN#4 ← phi( main/(byte*) SCREEN#1 ) + (byte) fillscreen::j#0 ← (byte/signed byte/word/signed word) 0 + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte) fillscreen::j#2 ← phi( fillscreen/(byte) fillscreen::j#0 fillscreen::@1/(byte) fillscreen::j#1 ) + (byte) fillscreen::c#1 ← phi( fillscreen/(byte) fillscreen::c#2 fillscreen::@1/(byte) fillscreen::c#1 ) + (byte*) SCREEN#2 ← phi( fillscreen/(byte*) SCREEN#4 fillscreen::@1/(byte*) SCREEN#2 ) + (byte*) fillscreen::SCREEN2#0 ← (byte*) SCREEN#2 + (word/signed word) 256 + (byte*) fillscreen::SCREEN3#0 ← (byte*) SCREEN#2 + (word/signed word) 512 + (byte*) fillscreen::SCREEN4#0 ← (byte*) SCREEN#2 + (word/signed word) 1000 + *((byte*) SCREEN#2 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + (boolean~) fillscreen::$3 ← (byte) fillscreen::j#1 != (byte/signed byte/word/signed word) 0 + if((boolean~) fillscreen::$3) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @2 + +Not aliassing across scopes: SCREEN#1 SCREEN#0 +Not aliassing across scopes: fillscreen::c#0 main::c#0 +Not aliassing across scopes: SCREEN#4 SCREEN#1 +Not aliassing across scopes: fillscreen::c#2 fillscreen::c#0 +Self Phi Eliminated (byte*) SCREEN#2 +Self Phi Eliminated (byte) fillscreen::c#1 +Succesful SSA optimization Pass2SelfPhiElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← ((byte*)) (word/signed word) 1024 + to:@2 +main: scope:[main] from @2 + (byte*) SCREEN#1 ← phi( @2/(byte*) SCREEN#0 ) + (byte) main::c#0 ← *((byte*) SCREEN#1) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@return +main::@return: scope:[main] from main + return + to:@return +fillscreen: scope:[fillscreen] from main + (byte) fillscreen::c#2 ← phi( main/(byte) fillscreen::c#0 ) + (byte*) SCREEN#4 ← phi( main/(byte*) SCREEN#1 ) + (byte) fillscreen::j#0 ← (byte/signed byte/word/signed word) 0 + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte) fillscreen::j#2 ← phi( fillscreen/(byte) fillscreen::j#0 fillscreen::@1/(byte) fillscreen::j#1 ) + (byte) fillscreen::c#1 ← phi( fillscreen/(byte) fillscreen::c#2 ) + (byte*) SCREEN#2 ← phi( fillscreen/(byte*) SCREEN#4 ) + (byte*) fillscreen::SCREEN2#0 ← (byte*) SCREEN#2 + (word/signed word) 256 + (byte*) fillscreen::SCREEN3#0 ← (byte*) SCREEN#2 + (word/signed word) 512 + (byte*) fillscreen::SCREEN4#0 ← (byte*) SCREEN#2 + (word/signed word) 1000 + *((byte*) SCREEN#2 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + *((byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#1 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + (boolean~) fillscreen::$3 ← (byte) fillscreen::j#1 != (byte/signed byte/word/signed word) 0 + if((boolean~) fillscreen::$3) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @2 + +Redundant Phi (byte*) SCREEN#1 (byte*) SCREEN#0 +Redundant Phi (byte*) SCREEN#4 (byte*) SCREEN#1 +Redundant Phi (byte) fillscreen::c#2 (byte) fillscreen::c#0 +Redundant Phi (byte*) SCREEN#2 (byte*) SCREEN#4 +Redundant Phi (byte) fillscreen::c#1 (byte) fillscreen::c#2 +Succesful SSA optimization Pass2RedundantPhiElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← ((byte*)) (word/signed word) 1024 + to:@2 +main: scope:[main] from @2 + (byte) main::c#0 ← *((byte*) SCREEN#0) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@return +main::@return: scope:[main] from main + return + to:@return +fillscreen: scope:[fillscreen] from main + (byte) fillscreen::j#0 ← (byte/signed byte/word/signed word) 0 + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte) fillscreen::j#2 ← phi( fillscreen/(byte) fillscreen::j#0 fillscreen::@1/(byte) fillscreen::j#1 ) + (byte*) fillscreen::SCREEN2#0 ← (byte*) SCREEN#0 + (word/signed word) 256 + (byte*) fillscreen::SCREEN3#0 ← (byte*) SCREEN#0 + (word/signed word) 512 + (byte*) fillscreen::SCREEN4#0 ← (byte*) SCREEN#0 + (word/signed word) 1000 + *((byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + (boolean~) fillscreen::$3 ← (byte) fillscreen::j#1 != (byte/signed byte/word/signed word) 0 + if((boolean~) fillscreen::$3) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @2 + +Simple Condition (boolean~) fillscreen::$3 if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 +Succesful SSA optimization Pass2ConditionalJumpSimplification +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← ((byte*)) (word/signed word) 1024 + to:@2 +main: scope:[main] from @2 + (byte) main::c#0 ← *((byte*) SCREEN#0) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@return +main::@return: scope:[main] from main + return + to:@return +fillscreen: scope:[fillscreen] from main + (byte) fillscreen::j#0 ← (byte/signed byte/word/signed word) 0 + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte) fillscreen::j#2 ← phi( fillscreen/(byte) fillscreen::j#0 fillscreen::@1/(byte) fillscreen::j#1 ) + (byte*) fillscreen::SCREEN2#0 ← (byte*) SCREEN#0 + (word/signed word) 256 + (byte*) fillscreen::SCREEN3#0 ← (byte*) SCREEN#0 + (word/signed word) 512 + (byte*) fillscreen::SCREEN4#0 ← (byte*) SCREEN#0 + (word/signed word) 1000 + *((byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @2 + +Constant (const byte*) SCREEN#0 = ((byte*))1024 +Constant (const byte) fillscreen::j#0 = 0 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@2 +main: scope:[main] from @2 + (byte) main::c#0 ← *((const byte*) SCREEN#0) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@return +main::@return: scope:[main] from main + return + to:@return +fillscreen: scope:[fillscreen] from main + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte) fillscreen::j#2 ← phi( fillscreen/(const byte) fillscreen::j#0 fillscreen::@1/(byte) fillscreen::j#1 ) + (byte*) fillscreen::SCREEN2#0 ← (const byte*) SCREEN#0 + (word/signed word) 256 + (byte*) fillscreen::SCREEN3#0 ← (const byte*) SCREEN#0 + (word/signed word) 512 + (byte*) fillscreen::SCREEN4#0 ← (const byte*) SCREEN#0 + (word/signed word) 1000 + *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @2 + +Constant (const byte*) fillscreen::SCREEN2#0 = SCREEN#0+256 +Constant (const byte*) fillscreen::SCREEN3#0 = SCREEN#0+512 +Constant (const byte*) fillscreen::SCREEN4#0 = SCREEN#0+1000 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@2 +main: scope:[main] from @2 + (byte) main::c#0 ← *((const byte*) SCREEN#0) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@return +main::@return: scope:[main] from main + return + to:@return +fillscreen: scope:[fillscreen] from main + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte) fillscreen::j#2 ← phi( fillscreen/(const byte) fillscreen::j#0 fillscreen::@1/(byte) fillscreen::j#1 ) + *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @2 + +Not aliassing across scopes: fillscreen::c#0 main::c#0 +Inlining constant with var siblings (const byte) fillscreen::j#0 +Inlining constant with var siblings (const byte) fillscreen::j#0 +Constant inlined fillscreen::j#0 = (byte/signed byte/word/signed word) 0 +Succesful SSA optimization Pass2ConstantInlining +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@2 +main: scope:[main] from @2 + (byte) main::c#0 ← *((const byte*) SCREEN#0) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@return +main::@return: scope:[main] from main + return + to:@return +fillscreen: scope:[fillscreen] from main + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + (byte) fillscreen::j#2 ← phi( fillscreen/(byte/signed byte/word/signed word) 0 fillscreen::@1/(byte) fillscreen::j#1 ) + *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +@2: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @2 + +FINAL SYMBOL TABLE +(label) @2 +(label) @begin +(label) @end +(byte*) SCREEN +(const byte*) SCREEN#0 = ((byte*))(word/signed word) 1024 +(void()) fillscreen((byte) fillscreen::c) +(label) fillscreen::@1 +(label) fillscreen::@return +(byte*) fillscreen::SCREEN2 +(const byte*) fillscreen::SCREEN2#0 = (const byte*) SCREEN#0+(word/signed word) 256 +(byte*) fillscreen::SCREEN3 +(const byte*) fillscreen::SCREEN3#0 = (const byte*) SCREEN#0+(word/signed word) 512 +(byte*) fillscreen::SCREEN4 +(const byte*) fillscreen::SCREEN4#0 = (const byte*) SCREEN#0+(word/signed word) 1000 +(byte) fillscreen::c +(byte) fillscreen::c#0 +(byte) fillscreen::j +(byte) fillscreen::j#1 +(byte) fillscreen::j#2 +(void()) main() +(label) main::@return +(byte) main::c +(byte) main::c#0 + +Block Sequence Planned @begin @2 @end main main::@return fillscreen fillscreen::@1 fillscreen::@return +Added new block during phi lifting fillscreen::@3(between fillscreen::@1 and fillscreen::@1) +Block Sequence Planned @begin @2 @end main main::@return fillscreen fillscreen::@1 fillscreen::@return fillscreen::@3 +CONTROL FLOW GRAPH - PHI LIFTED +@begin: scope:[] from + to:@2 +@2: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @2 +main: scope:[main] from @2 + (byte) main::c#0 ← *((const byte*) SCREEN#0) + (byte) fillscreen::c#0 ← (byte) main::c#0 + call fillscreen param-assignment + to:main::@return +main::@return: scope:[main] from main + return + to:@return +fillscreen: scope:[fillscreen] from main + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@3 + (byte) fillscreen::j#2 ← phi( fillscreen/(byte/signed byte/word/signed word) 0 fillscreen::@3/(byte~) fillscreen::j#3 ) + *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 + (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 + if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@3 + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + return + to:@return +fillscreen::@3: scope:[fillscreen] from fillscreen::@1 + (byte~) fillscreen::j#3 ← (byte) fillscreen::j#1 + to:fillscreen::@1 + +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of fillscreen +CALL GRAPH +Calls in [] to main:2 +Calls in [main] to fillscreen:6 + +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +CONTROL FLOW GRAPH - LIVE RANGES FOUND +@begin: scope:[] from + [0] phi() [ ] + to:@2 +@2: scope:[] from @begin + [1] phi() [ ] + [2] call main param-assignment [ ] + to:@end +@end: scope:[] from @2 + [3] phi() [ ] +main: scope:[main] from @2 + [4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] + [5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] + [6] call fillscreen param-assignment [ ] + to:main::@return +main::@return: scope:[main] from main + [7] return [ ] + to:@return +fillscreen: scope:[fillscreen] from main + [8] phi() [ fillscreen::c#0 ] + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@3 + [9] (byte) fillscreen::j#2 ← phi( fillscreen/(byte/signed byte/word/signed word) 0 fillscreen::@3/(byte~) fillscreen::j#3 ) [ fillscreen::c#0 fillscreen::j#2 ] + [10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] + [11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] + [12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] + [13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] + [14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] + [15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@3 [ fillscreen::c#0 fillscreen::j#1 ] + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + [16] return [ ] + to:@return +fillscreen::@3: scope:[fillscreen] from fillscreen::@1 + [17] (byte~) fillscreen::j#3 ← (byte) fillscreen::j#1 [ fillscreen::c#0 fillscreen::j#3 ] + to:fillscreen::@1 + +Created 1 initial phi equivalence classes +Coalesced [17] fillscreen::j#3 ← fillscreen::j#1 +Coalesced down to 1 phi equivalence classes +Culled Empty Block (label) fillscreen::@3 +Block Sequence Planned @begin @2 @end main main::@return fillscreen fillscreen::@1 fillscreen::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of fillscreen +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES +@begin: scope:[] from + [0] phi() [ ] + to:@2 +@2: scope:[] from @begin + [1] phi() [ ] + [2] call main param-assignment [ ] + to:@end +@end: scope:[] from @2 + [3] phi() [ ] +main: scope:[main] from @2 + [4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] + [5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] + [6] call fillscreen param-assignment [ ] + to:main::@return +main::@return: scope:[main] from main + [7] return [ ] + to:@return +fillscreen: scope:[fillscreen] from main + [8] phi() [ fillscreen::c#0 ] + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + [9] (byte) fillscreen::j#2 ← phi( fillscreen/(byte/signed byte/word/signed word) 0 fillscreen::@1/(byte) fillscreen::j#1 ) [ fillscreen::c#0 fillscreen::j#2 ] + [10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] + [11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] + [12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] + [13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] + [14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] + [15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 [ fillscreen::c#0 fillscreen::j#1 ] + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + [16] return [ ] + to:@return + +CONTROL FLOW GRAPH - PHI MEM COALESCED +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@2 +@2: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @2 + [3] phi() [ ] ( ) +main: scope:[main] from @2 + [4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] ( main:2 [ main::c#0 ] ) + [5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] ( main:2 [ fillscreen::c#0 ] ) + [6] call fillscreen param-assignment [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main + [7] return [ ] ( main:2 [ ] ) + to:@return +fillscreen: scope:[fillscreen] from main + [8] phi() [ fillscreen::c#0 ] ( main:2::fillscreen:6 [ fillscreen::c#0 ] ) + to:fillscreen::@1 +fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1 + [9] (byte) fillscreen::j#2 ← phi( fillscreen/(byte/signed byte/word/signed word) 0 fillscreen::@1/(byte) fillscreen::j#1 ) [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) + [10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) + [11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) + [12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) + [13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) + [14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) + [15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) + to:fillscreen::@return +fillscreen::@return: scope:[fillscreen] from fillscreen::@1 + [16] return [ ] ( main:2::fillscreen:6 [ ] ) + to:@return + +DOMINATORS +@begin dominated by @begin +@2 dominated by @2 @begin +@end dominated by @2 @begin @end +main dominated by @2 @begin main +main::@return dominated by main::@return @2 @begin main +fillscreen dominated by @2 @begin fillscreen main +fillscreen::@1 dominated by @2 @begin fillscreen main fillscreen::@1 +fillscreen::@return dominated by @2 @begin fillscreen main fillscreen::@1 fillscreen::@return + +Found back edge: Loop head: fillscreen::@1 tails: fillscreen::@1 blocks: null +Populated: Loop head: fillscreen::@1 tails: fillscreen::@1 blocks: fillscreen::@1 +NATURAL LOOPS +Loop head: fillscreen::@1 tails: fillscreen::@1 blocks: fillscreen::@1 + +Found 0 loops in scope [] +Found 0 loops in scope [main] +Found 1 loops in scope [fillscreen] + Loop head: fillscreen::@1 tails: fillscreen::@1 blocks: fillscreen::@1 +NATURAL LOOPS WITH DEPTH +Loop head: fillscreen::@1 tails: fillscreen::@1 blocks: fillscreen::@1 depth: 1 + + +VARIABLE REGISTER WEIGHTS +(byte*) SCREEN +(void()) fillscreen((byte) fillscreen::c) +(byte*) fillscreen::SCREEN2 +(byte*) fillscreen::SCREEN3 +(byte*) fillscreen::SCREEN4 +(byte) fillscreen::c +(byte) fillscreen::c#0 5.111111111111112 +(byte) fillscreen::j +(byte) fillscreen::j#1 16.5 +(byte) fillscreen::j#2 13.2 +(void()) main() +(byte) main::c +(byte) main::c#0 4.0 + +Initial phi equivalence classes +[ fillscreen::j#2 fillscreen::j#1 ] +Added variable main::c#0 to zero page equivalence class [ main::c#0 ] +Added variable fillscreen::c#0 to zero page equivalence class [ fillscreen::c#0 ] +Complete equivalence classes +[ fillscreen::j#2 fillscreen::j#1 ] +[ main::c#0 ] +[ fillscreen::c#0 ] +Allocated zp ZP_BYTE:2 [ fillscreen::j#2 fillscreen::j#1 ] +Allocated zp ZP_BYTE:3 [ main::c#0 ] +Allocated zp ZP_BYTE:4 [ fillscreen::c#0 ] +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +b2_from_bbegin: + jmp b2 +//SEG4 @2 +b2: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + .label c = 3 + //SEG9 [4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] ( main:2 [ main::c#0 ] ) -- zpby1=_deref_cowo1 + lda SCREEN + sta c + //SEG10 [5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] ( main:2 [ fillscreen::c#0 ] ) -- zpby1=zpby2 + lda c + sta fillscreen.c + //SEG11 [6] call fillscreen param-assignment [ ] ( main:2 [ ] ) + //SEG12 [8] phi from main to fillscreen [phi:main->fillscreen] + fillscreen_from_main: + jsr fillscreen + jmp breturn + //SEG13 main::@return + breturn: + //SEG14 [7] return [ ] ( main:2 [ ] ) + rts +} +//SEG15 fillscreen +fillscreen: { + .const SCREEN2 = SCREEN+$100 + .const SCREEN3 = SCREEN+$200 + .const SCREEN4 = SCREEN+$3e8 + .label c = 4 + .label j = 2 + //SEG16 [9] phi from fillscreen to fillscreen::@1 [phi:fillscreen->fillscreen::@1] + b1_from_fillscreen: + //SEG17 [9] phi (byte) fillscreen::j#2 = (byte/signed byte/word/signed word) 0 [phi:fillscreen->fillscreen::@1#0] -- zpby1=coby1 + lda #0 + sta j + jmp b1 + //SEG18 [9] phi from fillscreen::@1 to fillscreen::@1 [phi:fillscreen::@1->fillscreen::@1] + b1_from_b1: + //SEG19 [9] phi (byte) fillscreen::j#2 = (byte) fillscreen::j#1 [phi:fillscreen::@1->fillscreen::@1#0] -- register_copy + jmp b1 + //SEG20 fillscreen::@1 + b1: + //SEG21 [10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_zpby1=zpby2 + lda c + ldx j + sta SCREEN,x + //SEG22 [11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_zpby1=zpby2 + lda c + ldx j + sta SCREEN2,x + //SEG23 [12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_zpby1=zpby2 + lda c + ldx j + sta SCREEN3,x + //SEG24 [13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_zpby1=zpby2 + lda c + ldx j + sta SCREEN4,x + //SEG25 [14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- zpby1=_inc_zpby1 + inc j + //SEG26 [15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- zpby1_neq_0_then_la1 + lda j + bne b1_from_b1 + jmp breturn + //SEG27 fillscreen::@return + breturn: + //SEG28 [16] return [ ] ( main:2::fillscreen:6 [ ] ) + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Potential registers zp ZP_BYTE:2 [ fillscreen::j#2 fillscreen::j#1 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:3 [ main::c#0 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:4 [ fillscreen::c#0 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [fillscreen] 29.7: zp ZP_BYTE:2 [ fillscreen::j#2 fillscreen::j#1 ] 5.11: zp ZP_BYTE:4 [ fillscreen::c#0 ] +Uplift Scope [main] 4: zp ZP_BYTE:3 [ main::c#0 ] +Uplift Scope [] + +Uplifting [fillscreen] best 418 combination reg byte x [ fillscreen::j#2 fillscreen::j#1 ] reg byte a [ fillscreen::c#0 ] +Uplifting [main] best 412 combination reg byte a [ main::c#0 ] +Uplifting [] best 412 combination +Removing instruction jmp b2 +Removing instruction jmp bend +Removing instruction jmp breturn +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +b2_from_bbegin: +//SEG4 @2 +b2: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @2 to @end [phi:@2->@end] +bend_from_b2: +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 [4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] ( main:2 [ main::c#0 ] ) -- aby=_deref_cowo1 + lda SCREEN + //SEG10 [5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] ( main:2 [ fillscreen::c#0 ] ) + // (byte) fillscreen::c#0 = (byte) main::c#0 // register copy reg byte a + //SEG11 [6] call fillscreen param-assignment [ ] ( main:2 [ ] ) + //SEG12 [8] phi from main to fillscreen [phi:main->fillscreen] + fillscreen_from_main: + jsr fillscreen + //SEG13 main::@return + breturn: + //SEG14 [7] return [ ] ( main:2 [ ] ) + rts +} +//SEG15 fillscreen +fillscreen: { + .const SCREEN2 = SCREEN+$100 + .const SCREEN3 = SCREEN+$200 + .const SCREEN4 = SCREEN+$3e8 + //SEG16 [9] phi from fillscreen to fillscreen::@1 [phi:fillscreen->fillscreen::@1] + b1_from_fillscreen: + //SEG17 [9] phi (byte) fillscreen::j#2 = (byte/signed byte/word/signed word) 0 [phi:fillscreen->fillscreen::@1#0] -- xby=coby1 + ldx #0 + jmp b1 + //SEG18 [9] phi from fillscreen::@1 to fillscreen::@1 [phi:fillscreen::@1->fillscreen::@1] + b1_from_b1: + //SEG19 [9] phi (byte) fillscreen::j#2 = (byte) fillscreen::j#1 [phi:fillscreen::@1->fillscreen::@1#0] -- register_copy + //SEG20 fillscreen::@1 + b1: + //SEG21 [10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN,x + //SEG22 [11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN2,x + //SEG23 [12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN3,x + //SEG24 [13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN4,x + //SEG25 [14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- xby=_inc_xby + inx + //SEG26 [15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- xby_neq_0_then_la1 + cpx #0 + bne b1_from_b1 + //SEG27 fillscreen::@return + breturn: + //SEG28 [16] return [ ] ( main:2::fillscreen:6 [ ] ) + rts +} + +Replacing label b1_from_b1 with b1 +Removing instruction bbegin: +Removing instruction b2_from_bbegin: +Removing instruction bend_from_b2: +Removing instruction b1_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 +//SEG2 @begin +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +//SEG4 @2 +b2: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @2 to @end [phi:@2->@end] +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 [4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] ( main:2 [ main::c#0 ] ) -- aby=_deref_cowo1 + lda SCREEN + //SEG10 [5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] ( main:2 [ fillscreen::c#0 ] ) + // (byte) fillscreen::c#0 = (byte) main::c#0 // register copy reg byte a + //SEG11 [6] call fillscreen param-assignment [ ] ( main:2 [ ] ) + //SEG12 [8] phi from main to fillscreen [phi:main->fillscreen] + fillscreen_from_main: + jsr fillscreen + //SEG13 main::@return + breturn: + //SEG14 [7] return [ ] ( main:2 [ ] ) + rts +} +//SEG15 fillscreen +fillscreen: { + .const SCREEN2 = SCREEN+$100 + .const SCREEN3 = SCREEN+$200 + .const SCREEN4 = SCREEN+$3e8 + //SEG16 [9] phi from fillscreen to fillscreen::@1 [phi:fillscreen->fillscreen::@1] + b1_from_fillscreen: + //SEG17 [9] phi (byte) fillscreen::j#2 = (byte/signed byte/word/signed word) 0 [phi:fillscreen->fillscreen::@1#0] -- xby=coby1 + ldx #0 + jmp b1 + //SEG18 [9] phi from fillscreen::@1 to fillscreen::@1 [phi:fillscreen::@1->fillscreen::@1] + //SEG19 [9] phi (byte) fillscreen::j#2 = (byte) fillscreen::j#1 [phi:fillscreen::@1->fillscreen::@1#0] -- register_copy + //SEG20 fillscreen::@1 + b1: + //SEG21 [10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN,x + //SEG22 [11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN2,x + //SEG23 [12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN3,x + //SEG24 [13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN4,x + //SEG25 [14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- xby=_inc_xby + inx + //SEG26 [15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- xby_neq_0_then_la1 + cpx #0 + bne b1 + //SEG27 fillscreen::@return + breturn: + //SEG28 [16] return [ ] ( main:2::fillscreen:6 [ ] ) + rts +} + +Removing instruction b2: +Removing instruction bend: +Removing instruction fillscreen_from_main: +Removing instruction breturn: +Removing instruction b1_from_fillscreen: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 +//SEG2 @begin +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +//SEG4 @2 +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @2 to @end [phi:@2->@end] +//SEG7 @end +//SEG8 main +main: { + //SEG9 [4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] ( main:2 [ main::c#0 ] ) -- aby=_deref_cowo1 + lda SCREEN + //SEG10 [5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] ( main:2 [ fillscreen::c#0 ] ) + // (byte) fillscreen::c#0 = (byte) main::c#0 // register copy reg byte a + //SEG11 [6] call fillscreen param-assignment [ ] ( main:2 [ ] ) + //SEG12 [8] phi from main to fillscreen [phi:main->fillscreen] + jsr fillscreen + //SEG13 main::@return + //SEG14 [7] return [ ] ( main:2 [ ] ) + rts +} +//SEG15 fillscreen +fillscreen: { + .const SCREEN2 = SCREEN+$100 + .const SCREEN3 = SCREEN+$200 + .const SCREEN4 = SCREEN+$3e8 + //SEG16 [9] phi from fillscreen to fillscreen::@1 [phi:fillscreen->fillscreen::@1] + //SEG17 [9] phi (byte) fillscreen::j#2 = (byte/signed byte/word/signed word) 0 [phi:fillscreen->fillscreen::@1#0] -- xby=coby1 + ldx #0 + jmp b1 + //SEG18 [9] phi from fillscreen::@1 to fillscreen::@1 [phi:fillscreen::@1->fillscreen::@1] + //SEG19 [9] phi (byte) fillscreen::j#2 = (byte) fillscreen::j#1 [phi:fillscreen::@1->fillscreen::@1#0] -- register_copy + //SEG20 fillscreen::@1 + b1: + //SEG21 [10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN,x + //SEG22 [11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN2,x + //SEG23 [12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN3,x + //SEG24 [13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN4,x + //SEG25 [14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- xby=_inc_xby + inx + //SEG26 [15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- xby_neq_0_then_la1 + cpx #0 + bne b1 + //SEG27 fillscreen::@return + //SEG28 [16] return [ ] ( main:2::fillscreen:6 [ ] ) + rts +} + +Removing instruction jmp b1 +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 +//SEG2 @begin +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +//SEG4 @2 +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @2 to @end [phi:@2->@end] +//SEG7 @end +//SEG8 main +main: { + //SEG9 [4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] ( main:2 [ main::c#0 ] ) -- aby=_deref_cowo1 + lda SCREEN + //SEG10 [5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] ( main:2 [ fillscreen::c#0 ] ) + // (byte) fillscreen::c#0 = (byte) main::c#0 // register copy reg byte a + //SEG11 [6] call fillscreen param-assignment [ ] ( main:2 [ ] ) + //SEG12 [8] phi from main to fillscreen [phi:main->fillscreen] + jsr fillscreen + //SEG13 main::@return + //SEG14 [7] return [ ] ( main:2 [ ] ) + rts +} +//SEG15 fillscreen +fillscreen: { + .const SCREEN2 = SCREEN+$100 + .const SCREEN3 = SCREEN+$200 + .const SCREEN4 = SCREEN+$3e8 + //SEG16 [9] phi from fillscreen to fillscreen::@1 [phi:fillscreen->fillscreen::@1] + //SEG17 [9] phi (byte) fillscreen::j#2 = (byte/signed byte/word/signed word) 0 [phi:fillscreen->fillscreen::@1#0] -- xby=coby1 + ldx #0 + //SEG18 [9] phi from fillscreen::@1 to fillscreen::@1 [phi:fillscreen::@1->fillscreen::@1] + //SEG19 [9] phi (byte) fillscreen::j#2 = (byte) fillscreen::j#1 [phi:fillscreen::@1->fillscreen::@1#0] -- register_copy + //SEG20 fillscreen::@1 + b1: + //SEG21 [10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN,x + //SEG22 [11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN2,x + //SEG23 [12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN3,x + //SEG24 [13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN4,x + //SEG25 [14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- xby=_inc_xby + inx + //SEG26 [15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- xby_neq_0_then_la1 + cpx #0 + bne b1 + //SEG27 fillscreen::@return + //SEG28 [16] return [ ] ( main:2::fillscreen:6 [ ] ) + rts +} + +FINAL SYMBOL TABLE +(label) @2 +(label) @begin +(label) @end +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word) 1024 +(void()) fillscreen((byte) fillscreen::c) +(label) fillscreen::@1 +(label) fillscreen::@return +(byte*) fillscreen::SCREEN2 +(const byte*) fillscreen::SCREEN2#0 SCREEN2 = (const byte*) SCREEN#0+(word/signed word) 256 +(byte*) fillscreen::SCREEN3 +(const byte*) fillscreen::SCREEN3#0 SCREEN3 = (const byte*) SCREEN#0+(word/signed word) 512 +(byte*) fillscreen::SCREEN4 +(const byte*) fillscreen::SCREEN4#0 SCREEN4 = (const byte*) SCREEN#0+(word/signed word) 1000 +(byte) fillscreen::c +(byte) fillscreen::c#0 reg byte a 5.111111111111112 +(byte) fillscreen::j +(byte) fillscreen::j#1 reg byte x 16.5 +(byte) fillscreen::j#2 reg byte x 13.2 +(void()) main() +(label) main::@return +(byte) main::c +(byte) main::c#0 reg byte a 4.0 + +reg byte x [ fillscreen::j#2 fillscreen::j#1 ] +reg byte a [ main::c#0 ] +reg byte a [ fillscreen::c#0 ] + +FINAL CODE +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 +//SEG2 @begin +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +//SEG4 @2 +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @2 to @end [phi:@2->@end] +//SEG7 @end +//SEG8 main +main: { + //SEG9 [4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] ( main:2 [ main::c#0 ] ) -- aby=_deref_cowo1 + lda SCREEN + //SEG10 [5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] ( main:2 [ fillscreen::c#0 ] ) + // (byte) fillscreen::c#0 = (byte) main::c#0 // register copy reg byte a + //SEG11 [6] call fillscreen param-assignment [ ] ( main:2 [ ] ) + //SEG12 [8] phi from main to fillscreen [phi:main->fillscreen] + jsr fillscreen + //SEG13 main::@return + //SEG14 [7] return [ ] ( main:2 [ ] ) + rts +} +//SEG15 fillscreen +fillscreen: { + .const SCREEN2 = SCREEN+$100 + .const SCREEN3 = SCREEN+$200 + .const SCREEN4 = SCREEN+$3e8 + //SEG16 [9] phi from fillscreen to fillscreen::@1 [phi:fillscreen->fillscreen::@1] + //SEG17 [9] phi (byte) fillscreen::j#2 = (byte/signed byte/word/signed word) 0 [phi:fillscreen->fillscreen::@1#0] -- xby=coby1 + ldx #0 + //SEG18 [9] phi from fillscreen::@1 to fillscreen::@1 [phi:fillscreen::@1->fillscreen::@1] + //SEG19 [9] phi (byte) fillscreen::j#2 = (byte) fillscreen::j#1 [phi:fillscreen::@1->fillscreen::@1#0] -- register_copy + //SEG20 fillscreen::@1 + b1: + //SEG21 [10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN,x + //SEG22 [11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN2,x + //SEG23 [12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN3,x + //SEG24 [13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN4,x + //SEG25 [14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- xby=_inc_xby + inx + //SEG26 [15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] ) -- xby_neq_0_then_la1 + cpx #0 + bne b1 + //SEG27 fillscreen::@return + //SEG28 [16] return [ ] ( main:2::fillscreen:6 [ ] ) + rts +} + diff --git a/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.sym b/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.sym new file mode 100644 index 000000000..059ea7133 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/fillscreen.sym @@ -0,0 +1,27 @@ +(label) @2 +(label) @begin +(label) @end +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word) 1024 +(void()) fillscreen((byte) fillscreen::c) +(label) fillscreen::@1 +(label) fillscreen::@return +(byte*) fillscreen::SCREEN2 +(const byte*) fillscreen::SCREEN2#0 SCREEN2 = (const byte*) SCREEN#0+(word/signed word) 256 +(byte*) fillscreen::SCREEN3 +(const byte*) fillscreen::SCREEN3#0 SCREEN3 = (const byte*) SCREEN#0+(word/signed word) 512 +(byte*) fillscreen::SCREEN4 +(const byte*) fillscreen::SCREEN4#0 SCREEN4 = (const byte*) SCREEN#0+(word/signed word) 1000 +(byte) fillscreen::c +(byte) fillscreen::c#0 reg byte a 5.111111111111112 +(byte) fillscreen::j +(byte) fillscreen::j#1 reg byte x 16.5 +(byte) fillscreen::j#2 reg byte x 13.2 +(void()) main() +(label) main::@return +(byte) main::c +(byte) main::c#0 reg byte a 4.0 + +reg byte x [ fillscreen::j#2 fillscreen::j#1 ] +reg byte a [ main::c#0 ] +reg byte a [ fillscreen::c#0 ] diff --git a/src/main/java/dk/camelot64/kickc/test/unused-vars.kc b/src/main/java/dk/camelot64/kickc/test/unused-vars.kc new file mode 100644 index 000000000..e9d492035 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/unused-vars.kc @@ -0,0 +1,29 @@ +// used vars +const byte* SCREEN = $0400; +byte b=0; + +// unused vars +const byte* BGCOL = $d021; +byte[] msg = "hello world@"; +byte[] arr = { 7, 8, 9}; +byte c=1; +word d=1000; + +void main() { + // used vars + byte col=2; + byte* COLS=$d800; + // unused vars + byte e=3+3+3; + word f=2000+2000+d; + byte[] g = {4, 5, 6}; + byte[] h = "goodbye sky "; + + for(byte i : 0..100) { + // the last unused var + signed byte x = -13; + COLS[i] = col; + SCREEN[i] = b; + } + +} diff --git a/src/main/java/dk/camelot64/kickc/test/unused.kc b/src/main/java/dk/camelot64/kickc/test/unused.kc deleted file mode 100644 index 82a3d1071..000000000 --- a/src/main/java/dk/camelot64/kickc/test/unused.kc +++ /dev/null @@ -1,18 +0,0 @@ -byte *SCREEN = $0400; - -byte c = (*SCREEN); -fillscreen(c); - -void fillscreen(byte c) { - byte j=0; - do { - byte* SCREEN2 = SCREEN+$100; - byte* SCREEN3 = SCREEN+$200; - byte* SCREEN4 = SCREEN+$3e8; - SCREEN[j] = c; - SCREEN2[j] = c; - SCREEN3[j] = c; - SCREEN4[j] = c; - } while(++j!=0) -} -