diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index 3368cddf0..2f38a8dfe 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -222,6 +222,7 @@ public class Compiler { loopUnrolling.add(new Pass3StatementInfos(program)); loopUnrolling.add(new Pass2DominatorsAnalysis(program)); loopUnrolling.add(new Pass2LoopAnalysis(program)); + loopUnrolling.add(new Pass2LoopUnrollPhiPrepare(program)); loopUnrolling.add(new Pass2LoopUnroll(program)); pass2OptimizeSSA(loopUnrolling); } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2LoopUnroll.java b/src/main/java/dk/camelot64/kickc/passes/Pass2LoopUnroll.java index 0b6db7849..bfa92078f 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2LoopUnroll.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2LoopUnroll.java @@ -3,7 +3,6 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.*; import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementConditionalJump; -import dk.camelot64.kickc.model.statements.StatementInfos; import dk.camelot64.kickc.model.statements.StatementPhiBlock; import dk.camelot64.kickc.model.symbols.Label; import dk.camelot64.kickc.model.symbols.Variable; @@ -25,7 +24,7 @@ public class Pass2LoopUnroll extends Pass2SsaOptimization { public boolean step() { // Look for loops to unroll NaturalLoopSet loops = getProgram().getLoopSet(); - List unrollLoopCandidates = findUnrollLoopCandidates(loops); + List unrollLoopCandidates = findUnrollLoopCandidates(getProgram(), loops); // Is there any unrolling to do? if(unrollLoopCandidates.isEmpty()) { return false; @@ -82,51 +81,6 @@ public class Pass2LoopUnroll extends Pass2SsaOptimization { loopSuccessorPredecessors.add(block.getLabel()); } } - // - Add any needed PHI-statements to the successors - StatementInfos statementInfos = getProgram().getStatementInfos(); - for(VariableRef definedVarRef : definedToNewVar.keySet()) { - - // Find out if the variable is ever referenced outside the loop - boolean referencedOutsideLoop = false; - Collection varRefStatements = variableReferenceInfos.getVarRefStatements(definedVarRef); - for(Integer varRefStatement : varRefStatements) { - ControlFlowBlock refBlock = statementInfos.getBlock(varRefStatement); - if(!unrollLoop.getBlocks().contains(refBlock.getLabel())) { - referencedOutsideLoop = true; - break; - } - } - if(referencedOutsideLoop) { - for(int i = 0; i < loopSuccessors.size(); i++) { - LabelRef successorBlockRef = loopSuccessors.get(i); - LabelRef successorPredecessorRef = loopSuccessorPredecessors.get(i); - ControlFlowBlock successorBlock = getGraph().getBlock(successorBlockRef); - StatementPhiBlock phiBlock = successorBlock.getPhiBlock(); - - // Look for a phi-variable - boolean phiFound = false; - for(StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) { - if(phiVariable.getVariable().isVersion() && definedVarRef.isVersion()) { - if(phiVariable.getVariable().getFullNameUnversioned().equals(definedVarRef.getFullNameUnversioned())) { - phiFound = true; - } - } - } - if(!phiFound) { - Variable definedVar = getScope().getVariable(definedVarRef); - Variable newVar = ((VariableVersion) definedVar).getVersionOf().createVersion(); - StatementPhiBlock.PhiVariable newPhiVar = phiBlock.addPhiVariable(newVar.getRef()); - newPhiVar.setrValue(successorPredecessorRef, definedVarRef); - getLog().append("Missing PHI for " + definedVarRef.getFullName() + " in block " + successorBlock.getLabel() + " - " + phiBlock.toString(getProgram(), false)); - - // TODO: Replace all references to definedVarRef outside loop to newVar! - - } - } - } - } - - getLog().append(getGraph().toString(getProgram())); // 1. Copy all loop blocks to create the "rest of the loop" and modifying the existing loop to only be the first iteration) // - Unroll Statements (copy all statements, replace symbols properly (with the new versions / the versions assigned in the existing loop) @@ -203,9 +157,9 @@ public class Pass2LoopUnroll extends Pass2SsaOptimization { * @param loops All loops identified in the program * @return All loops declared to be unrolled */ - private List findUnrollLoopCandidates(NaturalLoopSet loops) { + static List findUnrollLoopCandidates(Program program, NaturalLoopSet loops) { List unrollLoopCandidates = new ArrayList<>(); - for(ControlFlowBlock block : getGraph().getAllBlocks()) { + for(ControlFlowBlock block : program.getGraph().getAllBlocks()) { for(Statement statement : block.getStatements()) { if(statement instanceof StatementConditionalJump) { if(((StatementConditionalJump) statement).isDeclaredUnroll()) { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2LoopUnrollPhiPrepare.java b/src/main/java/dk/camelot64/kickc/passes/Pass2LoopUnrollPhiPrepare.java new file mode 100644 index 000000000..ba778c7ae --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2LoopUnrollPhiPrepare.java @@ -0,0 +1,127 @@ +package dk.camelot64.kickc.passes; + +import dk.camelot64.kickc.model.*; +import dk.camelot64.kickc.model.statements.Statement; +import dk.camelot64.kickc.model.statements.StatementInfos; +import dk.camelot64.kickc.model.statements.StatementPhiBlock; +import dk.camelot64.kickc.model.symbols.Variable; +import dk.camelot64.kickc.model.symbols.VariableVersion; +import dk.camelot64.kickc.model.values.LabelRef; +import dk.camelot64.kickc.model.values.VariableRef; + +import java.util.*; + +/** + * Prepare for unrolling loops declared as inline. + * This is done byensuring that all variables defined inside the loops and used outside the loop is passed through a PHI-functions + * upon loop exit thus ensuring that these variables are only used inside the loop and in the PHI-function. + * This makes it much easier to perform the unrolling as only a few parts of the program must be modified. + */ +public class Pass2LoopUnrollPhiPrepare extends Pass2SsaOptimization { + + public Pass2LoopUnrollPhiPrepare(Program program) { + super(program); + } + + @Override + public boolean step() { + // Look for loops to unroll + NaturalLoopSet loops = getProgram().getLoopSet(); + List unrollLoopCandidates = Pass2LoopUnroll.findUnrollLoopCandidates(getProgram(), loops); + // Is there any unrolling to do? + if(unrollLoopCandidates.isEmpty()) { + return false; + } + + VariableReferenceInfos variableReferenceInfos = getProgram().getVariableReferenceInfos(); + + for(NaturalLoop unrollLoop : unrollLoopCandidates) { + + + List unrollBlocks = new ArrayList<>(); + for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) { + if(unrollLoop.getBlocks().contains(block.getLabel())) { + unrollBlocks.add(block); + } + } + + List definedInLoop = new ArrayList<>(); + for(ControlFlowBlock block : unrollBlocks) { + for(Statement statement : block.getStatements()) { + Collection definedVars = variableReferenceInfos.getDefinedVars(statement); + for(VariableRef definedVarRef : definedVars) { + definedInLoop.add(definedVarRef); + getLog().append("Defined in loop: " + definedVarRef.getFullName()); + } + } + } + + // - Ensure that all variables assigned inside the loop has a PHI in successor blocks to the loop + // - Find loop successor blocks + List loopSuccessors = new ArrayList<>(); + List loopSuccessorPredecessors = new ArrayList<>(); + for(ControlFlowBlock block : unrollBlocks) { + if(block.getDefaultSuccessor() != null && !unrollLoop.getBlocks().contains(block.getDefaultSuccessor())) { + // Default successor is outside + loopSuccessors.add(block.getDefaultSuccessor()); + loopSuccessorPredecessors.add(block.getLabel()); + } + if(block.getConditionalSuccessor() != null && !unrollLoop.getBlocks().contains(block.getConditionalSuccessor())) { + // Default successor is outside + loopSuccessors.add(block.getConditionalSuccessor()); + loopSuccessorPredecessors.add(block.getLabel()); + } + } + // - Add any needed PHI-statements to the successors + StatementInfos statementInfos = getProgram().getStatementInfos(); + for(VariableRef definedVarRef : definedInLoop) { + + // Find out if the variable is ever referenced outside the loop + boolean referencedOutsideLoop = false; + Collection varRefStatements = variableReferenceInfos.getVarRefStatements(definedVarRef); + for(Integer varRefStatement : varRefStatements) { + ControlFlowBlock refBlock = statementInfos.getBlock(varRefStatement); + if(!unrollLoop.getBlocks().contains(refBlock.getLabel())) { + referencedOutsideLoop = true; + break; + } + } + if(referencedOutsideLoop) { + for(int i = 0; i < loopSuccessors.size(); i++) { + LabelRef successorBlockRef = loopSuccessors.get(i); + LabelRef successorPredecessorRef = loopSuccessorPredecessors.get(i); + ControlFlowBlock successorBlock = getGraph().getBlock(successorBlockRef); + StatementPhiBlock phiBlock = successorBlock.getPhiBlock(); + + // Look for a phi-variable + boolean phiFound = false; + for(StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) { + if(phiVariable.getVariable().isVersion() && definedVarRef.isVersion()) { + if(phiVariable.getVariable().getFullNameUnversioned().equals(definedVarRef.getFullNameUnversioned())) { + phiFound = true; + } + } + } + if(!phiFound) { + Variable definedVar = getScope().getVariable(definedVarRef); + Variable newVar = ((VariableVersion) definedVar).getVersionOf().createVersion(); + StatementPhiBlock.PhiVariable newPhiVar = phiBlock.addPhiVariable(newVar.getRef()); + newPhiVar.setrValue(successorPredecessorRef, definedVarRef); + getLog().append("Missing PHI for " + definedVarRef.getFullName() + " in block " + successorBlock.getLabel() + " - " + phiBlock.toString(getProgram(), false)); + + // TODO: Replace all references to definedVarRef outside loop to newVar! + + } + } + } + } + + } + + getLog().append(getGraph().toString(getProgram())); + + return false; + + } + +}