1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 02:54:41 +00:00

Loop unroll prepare now complete.

This commit is contained in:
jespergravgaard 2018-08-21 16:45:07 +02:00
parent 4f23ed5079
commit bbeb37ea61
4 changed files with 130 additions and 101 deletions

View File

@ -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();

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}