mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-20 23:30:43 +00:00
Loop unroll prepare now complete.
This commit is contained in:
parent
4f23ed5079
commit
bbeb37ea61
@ -2,7 +2,9 @@ package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -60,6 +62,22 @@ public class NaturalLoop {
|
||||
this.blocks = blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actual blocks (not refs)
|
||||
* @param graph The control flow graph containing the blocks
|
||||
* @return The blocks of the loop (in the same order as they appear in the control flow graph.)
|
||||
*/
|
||||
public List<ControlFlowBlock> getBlocks(ControlFlowGraph graph) {
|
||||
ArrayList<ControlFlowBlock> controlFlowBlocks = new ArrayList<>();
|
||||
for(ControlFlowBlock block : graph.getAllBlocks()) {
|
||||
if(getBlocks().contains(block.getLabel())) {
|
||||
controlFlowBlocks.add(block);
|
||||
}
|
||||
}
|
||||
return controlFlowBlocks;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
@ -14,7 +14,6 @@ import java.util.Map;
|
||||
/** A {@link ProgramValueIterator} that replaces symbols with their alias. */
|
||||
public class AliasReplacer implements ProgramValueHandler {
|
||||
|
||||
|
||||
/** true if anything has ben replaced. */
|
||||
private boolean replaced;
|
||||
|
||||
@ -40,6 +39,7 @@ public class AliasReplacer implements ProgramValueHandler {
|
||||
if(programValue.get() != null) {
|
||||
RValue replacement = getReplacement(programValue.get(), aliases);
|
||||
if(replacement != null) {
|
||||
// System.out.println("Replacing "+programValue.get() + " with " +replacement + " in " +currentStmt);
|
||||
programValue.set(replacement);
|
||||
this.replaced = true;
|
||||
}
|
||||
|
@ -33,60 +33,30 @@ public class Pass2LoopUnroll extends Pass2SsaOptimization {
|
||||
NaturalLoop unrollLoop = chooseUnrollLoop(unrollLoopCandidates);
|
||||
getLog().append("Unrolling loop " + unrollLoop);
|
||||
|
||||
List<ControlFlowBlock> unrollBlocks = new ArrayList<>();
|
||||
for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
if(unrollLoop.getBlocks().contains(block.getLabel())) {
|
||||
unrollBlocks.add(block);
|
||||
}
|
||||
}
|
||||
|
||||
// Unroll the first iteration of the loop
|
||||
|
||||
// 0. Unroll Symbols
|
||||
// - Create new versions of all symbols assigned inside the loop
|
||||
Map<VariableRef, VariableRef> definedToNewVar = new LinkedHashMap<>();
|
||||
VariableReferenceInfos variableReferenceInfos = getProgram().getVariableReferenceInfos();
|
||||
for(ControlFlowBlock block : unrollBlocks) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
Collection<VariableRef> definedVars = variableReferenceInfos.getDefinedVars(statement);
|
||||
for(VariableRef definedVarRef : definedVars) {
|
||||
Variable definedVar = getScope().getVariable(definedVarRef);
|
||||
Variable newVar;
|
||||
if(definedVarRef.isIntermediate()) {
|
||||
newVar = definedVar.getScope().addVariableIntermediate();
|
||||
} else if(definedVarRef.isVersion()) {
|
||||
newVar = ((VariableVersion) definedVar).getVersionOf().createVersion();
|
||||
} else {
|
||||
throw new RuntimeException("Error! Variable is not versioned or intermediate " + definedVar.toString(getProgram()));
|
||||
}
|
||||
definedToNewVar.put(definedVarRef, newVar.getRef());
|
||||
getLog().append("Defined in loop: " + definedVarRef.getFullName() + " -> " + newVar.getRef().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());
|
||||
for(VariableRef definedVarRef : getVarsDefinedInLoop(getProgram(), unrollLoop)) {
|
||||
Variable definedVar = getScope().getVariable(definedVarRef);
|
||||
Variable newVar;
|
||||
if(definedVarRef.isIntermediate()) {
|
||||
newVar = definedVar.getScope().addVariableIntermediate();
|
||||
} else if(definedVarRef.isVersion()) {
|
||||
newVar = ((VariableVersion) definedVar).getVersionOf().createVersion();
|
||||
} else {
|
||||
throw new RuntimeException("Error! Variable is not versioned or intermediate " + definedVar.toString(getProgram()));
|
||||
}
|
||||
definedToNewVar.put(definedVarRef, newVar.getRef());
|
||||
getLog().append("Defined in loop: " + definedVarRef.getFullName() + " -> " + newVar.getRef().getFullName());
|
||||
}
|
||||
|
||||
// 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)
|
||||
// - Includes unrolling PHI-statements properly
|
||||
// - Unroll Successors (loop-exit successors should point to the same exit, loop-internal successors should point to the new loop-internal block)
|
||||
for(ControlFlowBlock block : unrollBlocks) {
|
||||
for(ControlFlowBlock block : unrollLoop.getBlocks(getGraph())) {
|
||||
// Find the serial number
|
||||
int unrollSerial = 1;
|
||||
String unrollLabelName = block.getLabel() + "_" + unrollSerial;
|
||||
@ -151,6 +121,7 @@ public class Pass2LoopUnroll extends Pass2SsaOptimization {
|
||||
return unrollLoop;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find all loops declared for unrolling. This is done by examining all conditional jumps, which hold the loop unroll declaration.
|
||||
*
|
||||
@ -181,4 +152,60 @@ public class Pass2LoopUnroll extends Pass2SsaOptimization {
|
||||
}
|
||||
return unrollLoopCandidates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all variables defined inside a loop
|
||||
* @param program The program
|
||||
* @param loop The loop
|
||||
* @return All variables defined inside the blocks of the loop
|
||||
*/
|
||||
static List<VariableRef> getVarsDefinedInLoop(Program program, NaturalLoop loop) {
|
||||
VariableReferenceInfos variableReferenceInfos = program.getVariableReferenceInfos();
|
||||
List<VariableRef> definedInLoop = new ArrayList<>();
|
||||
for(ControlFlowBlock block : loop.getBlocks(program.getGraph())) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
Collection<VariableRef> definedVars = variableReferenceInfos.getDefinedVars(statement);
|
||||
for(VariableRef definedVarRef : definedVars) {
|
||||
definedInLoop.add(definedVarRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
return definedInLoop;
|
||||
}
|
||||
|
||||
/** Information about a block successing a loop - ie. a place where the flow of control leaves a loop. */
|
||||
public static class LoopSuccessorBlock {
|
||||
/** A block that is the sucessor to a block inside the loop. */
|
||||
LabelRef sucessor;
|
||||
/** The block inside the loop that is the predecessor of the loop sucessor block. */
|
||||
LabelRef predecessor;
|
||||
|
||||
public LoopSuccessorBlock(LabelRef sucessor, LabelRef predecessor) {
|
||||
this.sucessor = sucessor;
|
||||
this.predecessor = predecessor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all transitions where the flow of control leaves a loop
|
||||
* @param loop The loop to examine
|
||||
* @param graph The control flow graph
|
||||
* @return
|
||||
*/
|
||||
static List<LoopSuccessorBlock> getLoopSuccessorBlocks(NaturalLoop loop, ControlFlowGraph graph) {
|
||||
List<LoopSuccessorBlock> loopSuccessors = new ArrayList<>();
|
||||
for(ControlFlowBlock block : loop.getBlocks(graph)) {
|
||||
if(block.getDefaultSuccessor() != null && !loop.getBlocks().contains(block.getDefaultSuccessor())) {
|
||||
// Default successor is outside
|
||||
loopSuccessors.add(new LoopSuccessorBlock(block.getDefaultSuccessor(), block.getLabel()));
|
||||
}
|
||||
if(block.getConditionalSuccessor() != null && !loop.getBlocks().contains(block.getConditionalSuccessor())) {
|
||||
// Conditional successor is outside
|
||||
loopSuccessors.add(new LoopSuccessorBlock(block.getConditionalSuccessor(), block.getLabel()));
|
||||
}
|
||||
}
|
||||
return loopSuccessors;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,19 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
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.RValue;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Prepare for unrolling loops declared as inline.
|
||||
@ -33,63 +37,20 @@ public class Pass2LoopUnrollPhiPrepare extends Pass2SsaOptimization {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<VariableRef> definedInLoop = Pass2LoopUnroll.getVarsDefinedInLoop(getProgram(), unrollLoop);
|
||||
// - 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());
|
||||
}
|
||||
}
|
||||
List<Pass2LoopUnroll.LoopSuccessorBlock> loopSuccessors = Pass2LoopUnroll.getLoopSuccessorBlocks(unrollLoop, getGraph());
|
||||
// - 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);
|
||||
if(isReferencedOutsideLoop(definedVarRef, unrollLoop, getProgram())) {
|
||||
for(Pass2LoopUnroll.LoopSuccessorBlock loopSuccessor : loopSuccessors) {
|
||||
LabelRef successorBlockRef = loopSuccessor.sucessor;
|
||||
LabelRef successorPredecessorRef = loopSuccessor.predecessor;
|
||||
ControlFlowBlock successorBlock = getGraph().getBlock(successorBlockRef);
|
||||
StatementPhiBlock phiBlock = successorBlock.getPhiBlock();
|
||||
|
||||
@ -105,23 +66,46 @@ public class Pass2LoopUnrollPhiPrepare extends Pass2SsaOptimization {
|
||||
if(!phiFound) {
|
||||
Variable definedVar = getScope().getVariable(definedVarRef);
|
||||
Variable newVar = ((VariableVersion) definedVar).getVersionOf().createVersion();
|
||||
|
||||
// Replace all references to definedVarRef outside loop to newVar!
|
||||
LinkedHashMap<SymbolRef, RValue> aliases = new LinkedHashMap<>();
|
||||
aliases.put(definedVarRef, newVar.getRef());
|
||||
ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
if(currentBlock != null) {
|
||||
if(!unrollLoop.getBlocks().contains(currentBlock.getLabel())) {
|
||||
new AliasReplacer(aliases).execute(programValue, currentStmt, stmtIt, currentBlock);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Create the new phi-variable
|
||||
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("Creating PHI for " + definedVarRef.getFullName() + " in block " + successorBlock.getLabel() + " - " + phiBlock.toString(getProgram(), false));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getLog().append(getGraph().toString(getProgram()));
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
private static boolean isReferencedOutsideLoop(VariableRef definedVarRef, NaturalLoop unrollLoop, Program program) {
|
||||
boolean referencedOutsideLoop = false;
|
||||
VariableReferenceInfos variableReferenceInfos = program.getVariableReferenceInfos();
|
||||
Collection<Integer> varRefStatements = variableReferenceInfos.getVarRefStatements(definedVarRef);
|
||||
for(Integer varRefStatement : varRefStatements) {
|
||||
StatementInfos statementInfos = program.getStatementInfos();
|
||||
ControlFlowBlock refBlock = statementInfos.getBlock(varRefStatement);
|
||||
if(!unrollLoop.getBlocks().contains(refBlock.getLabel())) {
|
||||
referencedOutsideLoop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return referencedOutsideLoop;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user