mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-20 23:30:43 +00:00
Split unroll prepare into separate pass
This commit is contained in:
parent
b19bf2246e
commit
4f23ed5079
@ -222,6 +222,7 @@ public class Compiler {
|
|||||||
loopUnrolling.add(new Pass3StatementInfos(program));
|
loopUnrolling.add(new Pass3StatementInfos(program));
|
||||||
loopUnrolling.add(new Pass2DominatorsAnalysis(program));
|
loopUnrolling.add(new Pass2DominatorsAnalysis(program));
|
||||||
loopUnrolling.add(new Pass2LoopAnalysis(program));
|
loopUnrolling.add(new Pass2LoopAnalysis(program));
|
||||||
|
loopUnrolling.add(new Pass2LoopUnrollPhiPrepare(program));
|
||||||
loopUnrolling.add(new Pass2LoopUnroll(program));
|
loopUnrolling.add(new Pass2LoopUnroll(program));
|
||||||
pass2OptimizeSSA(loopUnrolling);
|
pass2OptimizeSSA(loopUnrolling);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package dk.camelot64.kickc.passes;
|
|||||||
import dk.camelot64.kickc.model.*;
|
import dk.camelot64.kickc.model.*;
|
||||||
import dk.camelot64.kickc.model.statements.Statement;
|
import dk.camelot64.kickc.model.statements.Statement;
|
||||||
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
|
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.statements.StatementPhiBlock;
|
||||||
import dk.camelot64.kickc.model.symbols.Label;
|
import dk.camelot64.kickc.model.symbols.Label;
|
||||||
import dk.camelot64.kickc.model.symbols.Variable;
|
import dk.camelot64.kickc.model.symbols.Variable;
|
||||||
@ -25,7 +24,7 @@ public class Pass2LoopUnroll extends Pass2SsaOptimization {
|
|||||||
public boolean step() {
|
public boolean step() {
|
||||||
// Look for loops to unroll
|
// Look for loops to unroll
|
||||||
NaturalLoopSet loops = getProgram().getLoopSet();
|
NaturalLoopSet loops = getProgram().getLoopSet();
|
||||||
List<NaturalLoop> unrollLoopCandidates = findUnrollLoopCandidates(loops);
|
List<NaturalLoop> unrollLoopCandidates = findUnrollLoopCandidates(getProgram(), loops);
|
||||||
// Is there any unrolling to do?
|
// Is there any unrolling to do?
|
||||||
if(unrollLoopCandidates.isEmpty()) {
|
if(unrollLoopCandidates.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
@ -82,51 +81,6 @@ public class Pass2LoopUnroll extends Pass2SsaOptimization {
|
|||||||
loopSuccessorPredecessors.add(block.getLabel());
|
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<Integer> 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)
|
// 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)
|
// - 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
|
* @param loops All loops identified in the program
|
||||||
* @return All loops declared to be unrolled
|
* @return All loops declared to be unrolled
|
||||||
*/
|
*/
|
||||||
private List<NaturalLoop> findUnrollLoopCandidates(NaturalLoopSet loops) {
|
static List<NaturalLoop> findUnrollLoopCandidates(Program program, NaturalLoopSet loops) {
|
||||||
List<NaturalLoop> unrollLoopCandidates = new ArrayList<>();
|
List<NaturalLoop> unrollLoopCandidates = new ArrayList<>();
|
||||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||||
for(Statement statement : block.getStatements()) {
|
for(Statement statement : block.getStatements()) {
|
||||||
if(statement instanceof StatementConditionalJump) {
|
if(statement instanceof StatementConditionalJump) {
|
||||||
if(((StatementConditionalJump) statement).isDeclaredUnroll()) {
|
if(((StatementConditionalJump) statement).isDeclaredUnroll()) {
|
||||||
|
@ -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<NaturalLoop> 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<ControlFlowBlock> unrollBlocks = new ArrayList<>();
|
||||||
|
for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||||
|
if(unrollLoop.getBlocks().contains(block.getLabel())) {
|
||||||
|
unrollBlocks.add(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<VariableRef> definedInLoop = new ArrayList<>();
|
||||||
|
for(ControlFlowBlock block : unrollBlocks) {
|
||||||
|
for(Statement statement : block.getStatements()) {
|
||||||
|
Collection<VariableRef> 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<LabelRef> loopSuccessors = new ArrayList<>();
|
||||||
|
List<LabelRef> 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<Integer> 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user