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

Added more simple optimizing passes

This commit is contained in:
Jesper Gravgaard 2017-05-14 11:30:46 +02:00
parent 73fa2839e0
commit b3fd0eb28c
17 changed files with 534 additions and 48 deletions

View File

@ -3,5 +3,4 @@ package dk.camelot64.kickc.icl;
/** SSA form constant value */
public interface Constant extends RValue {
}

View File

@ -15,4 +15,8 @@ public class ConstantDouble implements Constant {
public String toString() {
return Double.toString(number);
}
public Double getNumber() {
return number;
}
}

View File

@ -0,0 +1,59 @@
package dk.camelot64.kickc.icl;
import java.util.Collection;
/** Base visitor for iterating through a control flow graph */
public class ControlFlowGraphBaseVisitor<T> {
public T visitGraph(ControlFlowGraph graph) {
Collection<ControlFlowBlock> blocks = graph.getAllBlocks();
for (ControlFlowBlock block : blocks) {
this.visitBlock(block);
}
return null;
}
public T visitBlock(ControlFlowBlock block) {
for (Statement statement : block.getStatements()) {
this.visitStatement(statement);
}
return null;
}
public T visitStatement(Statement statement) {
if(statement instanceof StatementAssignment) {
return visitAssignment((StatementAssignment) statement);
} else if(statement instanceof StatementConditionalJump) {
return visitConditionalJump((StatementConditionalJump) statement);
} else if(statement instanceof StatementJump) {
return visitJump((StatementJump) statement);
} else if(statement instanceof StatementJumpTarget) {
return visitJumpTarget((StatementJumpTarget) statement);
} else if(statement instanceof StatementPhi) {
return visitPhi((StatementPhi) statement);
} else {
throw new RuntimeException("Unhandled statement type "+statement);
}
}
public T visitAssignment(StatementAssignment assignment) {
return null;
}
public T visitConditionalJump(StatementConditionalJump conditionalJump) {
return null;
}
public T visitJump(StatementJump jump) {
return null;
}
public T visitJumpTarget(StatementJumpTarget jumpTarget) {
return null;
}
public T visitPhi(StatementPhi phi) {
return null;
}
}

View File

@ -1,5 +1,5 @@
package dk.camelot64.kickc.icl;
/** Assignable value (capable of being on the left part of an assignment)*/
public interface LValue {
public interface LValue extends RValue {
}

View File

@ -0,0 +1,79 @@
package dk.camelot64.kickc.icl;
import java.util.HashMap;
import java.util.Map;
/** Compiler Pass eliminating alias assignments */
public class PassAliasElimination {
private SymbolTable symbolTable;
private ControlFlowGraph graph;
public PassAliasElimination(SymbolTable symbolTable, ControlFlowGraph graph) {
this.symbolTable = symbolTable;
this.graph = graph;
}
/**
* Eliminate alias assignments replacing them with the aliassed variable.
*/
public void eliminate() {
final Map<Variable, Variable> aliases = findAliases();
PassHelper.removeAssignments(graph, symbolTable, aliases.values());
PassHelper.replace(graph, aliases);
for (Variable var : aliases.keySet()) {
Variable alias = aliases.get(var);
System.out.println("Alias " + var + " " + alias);
}
}
/** Make sure aliases of other aliases are pointing to the final alias. */
private void finalizeAliases(Map<Variable, Variable> aliases) {
for (Variable variable : aliases.keySet()) {
Variable alias = aliases.get(variable);
while(aliases.get(alias)!=null) {
alias = aliases.get(alias);
}
aliases.put(variable, alias);
}
}
/**
* Find variables that have constant values.
* @return Map from Variable to the Constant value
*/
private Map<Variable, Variable> findAliases() {
final Map<Variable, Variable> aliases = new HashMap<>();
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitAssignment(StatementAssignment assignment) {
if (assignment.getLValue() instanceof VariableVersion || assignment.getLValue() instanceof VariableIntermediate) {
Variable variable = (Variable) assignment.getLValue();
if (assignment.getRValue1() == null && assignment.getOperator() == null && assignment.getRValue2() instanceof Variable) {
// Alias assignment
Variable alias = (Variable) assignment.getRValue2();
aliases.put(alias, variable);
}
}
return null;
}
@Override
public Void visitPhi(StatementPhi phi) {
if(phi.getPreviousVersions().size()==1) {
StatementPhi.PreviousSymbol previousSymbol = phi.getPreviousVersions().get(0);
if(previousSymbol.getRValue() instanceof Variable) {
VariableVersion variable = phi.getLValue();
Variable alias = (Variable) previousSymbol.getRValue();
aliases.put(alias, variable);
}
}
return null;
}
};
visitor.visitGraph(graph);
return aliases;
}
}

View File

@ -0,0 +1,144 @@
package dk.camelot64.kickc.icl;
import java.util.HashMap;
import java.util.Map;
/** Compiler Pass propagating constants in expressions eliminating constant variables */
public class PassConstantPropagation {
private SymbolTable symbolTable;
private ControlFlowGraph controlFlowGraph;
public PassConstantPropagation(SymbolTable symbolTable, ControlFlowGraph controlFlowGraph) {
this.symbolTable = symbolTable;
this.controlFlowGraph = controlFlowGraph;
}
/**
* Propagate constants, replacing variables with constants where possible.
* @return true if no more constant propagation is possible. (no constant propagation was performed)
* false if more constant propagation might be possible. (signalling another call)
*/
public void propagateConstants() {
boolean done;
do {
final Map<Variable, Constant> constants = findConstantVariables();
for (Variable constantVar : constants.keySet()) {
Constant constantValue = constants.get(constantVar);
System.out.println("Constant " + constantVar + " " + constantValue);
}
PassHelper.removeAssignments(controlFlowGraph, symbolTable, constants.keySet());
PassHelper.replace(controlFlowGraph, constants);
done = (constants.size()==0);
} while (!done);
}
/**
* Find variables that have constant values.
* @return Map from Variable to the Constant value
*/
private Map<Variable, Constant> findConstantVariables() {
final Map<Variable, Constant> constants = new HashMap<>();
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitAssignment(StatementAssignment assignment) {
if(assignment.getLValue() instanceof VariableVersion || assignment.getLValue() instanceof VariableIntermediate ) {
Variable variable = (Variable) assignment.getLValue();
if(assignment.getRValue1() == null && assignment.getRValue2() instanceof Constant) {
if(assignment.getOperator()==null) {
// Constant assignment
Constant constant = (Constant) assignment.getRValue2();
constants.put(variable, constant);
} else {
// Constant unary expression
Constant constant = calculateUnary(assignment.getOperator(), (Constant) assignment.getRValue2());
constants.put(variable, constant);
}
} else if(assignment.getRValue1() instanceof Constant && assignment.getRValue2() instanceof Constant) {
// Constant binary expression
Constant constant = calculateBinary(assignment.getOperator(), (Constant) assignment.getRValue1(), (Constant) assignment.getRValue2());
constants.put(variable, constant);
}
}
return null;
}
@Override
public Void visitPhi(StatementPhi phi) {
if(phi.getPreviousVersions().size()==1) {
StatementPhi.PreviousSymbol previousSymbol = phi.getPreviousVersions().get(0);
if(previousSymbol.getRValue() instanceof Constant) {
VariableVersion variable = phi.getLValue();
Constant constant = (Constant) previousSymbol.getRValue();
constants.put(variable, constant);
}
}
return null;
}
};
visitor.visitGraph(controlFlowGraph);
return constants;
}
public static Constant calculateBinary(Operator operator, Constant c1, Constant c2) {
switch(operator.getOperator()) {
case "-": {
if(c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
return new ConstantInteger(getInteger(c1) - getInteger(c2));
} else {
return new ConstantDouble(getDouble(c1) - getDouble(c2));
}
}
case "+": {
if(c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
return new ConstantInteger(getInteger(c1) + getInteger(c2));
} else {
return new ConstantDouble(getDouble(c1) + getDouble(c2));
}
}
default:
throw new RuntimeException("Unhandled Binary Operator "+operator.getOperator());
}
}
private static Integer getInteger(Constant constant) {
if(constant instanceof ConstantInteger) {
return ((ConstantInteger) constant).getNumber();
} else {
throw new RuntimeException("Type Mismatch. Constant is not an integer number "+constant);
}
}
private static Double getDouble(Constant constant) {
if(constant instanceof ConstantDouble) {
return ((ConstantDouble) constant).getNumber();
} else if(constant instanceof ConstantInteger) {
return ((ConstantInteger) constant).getNumber().doubleValue();
} else {
throw new RuntimeException("Type Mismatch. Constant is not a number "+constant);
}
}
public static Constant calculateUnary(Operator operator, Constant c) {
switch(operator.getOperator()) {
case "-": {
if(c instanceof ConstantInteger) {
ConstantInteger cInt = (ConstantInteger) c;
return new ConstantInteger(-cInt.getNumber());
} else if(c instanceof ConstantDouble) {
ConstantDouble cDoub = (ConstantDouble) c;
return new ConstantDouble(-cDoub.getNumber());
} else {
throw new RuntimeException("Type mismatch. Unary Minus cannot handle value "+c);
}
}
case "+": {
return c;
}
default:
throw new RuntimeException("Unhandled Unary Operator "+operator.getOperator());
}
}
}

View File

@ -0,0 +1,42 @@
package dk.camelot64.kickc.icl;
import java.util.*;
/** Pass that culls empty control flow blocks from the program */
public class PassCullEmptyBlocks {
private SymbolTable symbolTable;
private ControlFlowGraph graph;
public PassCullEmptyBlocks(SymbolTable symbolTable, ControlFlowGraph controlFlowGraph) {
this.symbolTable = symbolTable;
this.graph = controlFlowGraph;
}
public void cull() {
cullEmptyBlocks();
}
private void cullEmptyBlocks() {
for (Iterator<ControlFlowBlock> iterator = graph.getAllBlocks().iterator(); iterator.hasNext(); ) {
ControlFlowBlock block = iterator.next();
if (block.getStatements().isEmpty()) {
ControlFlowBlock successor = block.getDefaultSuccessor();
for (ControlFlowBlock predecessor : block.getPredecessors()) {
if (predecessor.getDefaultSuccessor().equals(block)) {
predecessor.setDefaultSuccessor(successor);
successor.addPredecessor(predecessor);
}
if (predecessor.getConditionalSuccessor().equals(block)) {
predecessor.setConditionalSuccessor(successor);
successor.addPredecessor(predecessor);
}
}
successor.removePredecessor(block);
iterator.remove();
symbolTable.remove(block.getLabel());
}
}
}
}

View File

@ -49,35 +49,9 @@ public class PassGenerateControlFlowGraph {
currentBlock.addStatement(statement);
}
}
cullEmptyBlocks();
return new ControlFlowGraph(blocks, firstBlock);
}
private void cullEmptyBlocks() {
List<ControlFlowBlock> remove = new ArrayList<>();
for (ControlFlowBlock block : blocks.values()) {
if(block.getStatements().isEmpty()) {
ControlFlowBlock successor = block.getDefaultSuccessor();
for (ControlFlowBlock predecessor : block.getPredecessors()) {
if(predecessor.getDefaultSuccessor().equals(block)) {
predecessor.setDefaultSuccessor(successor);
successor.addPredecessor(predecessor);
}
if(predecessor.getConditionalSuccessor().equals(block)) {
predecessor.setConditionalSuccessor(successor);
successor.addPredecessor(predecessor);
}
}
successor.removePredecessor(block);
remove.add(block);
}
}
for (ControlFlowBlock block : remove) {
blocks.remove(block.getLabel());
symbolTable.remove(block.getLabel());
}
}
private ControlFlowBlock getOrCreateBlock(Label label) {
ControlFlowBlock block = blocks.get(label);
if(block==null) {

View File

@ -34,7 +34,7 @@ public class PassGenerateSingleStaticAssignmentForm {
for (Statement statement : block.getStatements()) {
if (statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
LValue lValue = assignment.getlValue();
LValue lValue = assignment.getLValue();
if(lValue instanceof VariableUnversioned) {
// Assignment to a non-versioned non-intermediary variable
VariableUnversioned assignedSymbol = (VariableUnversioned) lValue;
@ -69,7 +69,7 @@ public class PassGenerateSingleStaticAssignmentForm {
}
}
// Update map of versions encountered in the block
LValue lValue = assignment.getlValue();
LValue lValue = assignment.getLValue();
if (lValue instanceof VariableVersion) {
VariableVersion versioned = (VariableVersion) lValue;
blockVersions.put(versioned.getVersionOf(), versioned);
@ -81,7 +81,6 @@ public class PassGenerateSingleStaticAssignmentForm {
block.addPhiStatement(blockNewPhis.get(symbol));
}
}
}
/**
@ -126,7 +125,7 @@ public class PassGenerateSingleStaticAssignmentForm {
if (statement instanceof StatementPhi) {
StatementPhi phi = (StatementPhi) statement;
if (phi.getPreviousVersions().isEmpty()) {
VariableVersion versioned = phi.getlValue();
VariableVersion versioned = phi.getLValue();
VariableUnversioned unversioned = versioned.getVersionOf();
for (ControlFlowBlock predecessor : block.getPredecessors()) {
VariableVersion previousSymbol = symbolMap.get(predecessor.getLabel()).get(unversioned);
@ -172,7 +171,7 @@ public class PassGenerateSingleStaticAssignmentForm {
for (Statement statement : block.getStatements()) {
if(statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
LValue lValue = assignment.getlValue();
LValue lValue = assignment.getLValue();
if(lValue instanceof VariableVersion) {
VariableVersion versioned = (VariableVersion) lValue;
Label label = block.getLabel();
@ -186,7 +185,7 @@ public class PassGenerateSingleStaticAssignmentForm {
}
} else if(statement instanceof StatementPhi) {
StatementPhi phi = (StatementPhi) statement;
VariableVersion versioned = phi.getlValue();
VariableVersion versioned = phi.getLValue();
VariableUnversioned unversioned = versioned.getVersionOf();
Label label = block.getLabel();
Map<VariableUnversioned, VariableVersion> blockMap = symbolMap.get(label);
@ -200,5 +199,4 @@ public class PassGenerateSingleStaticAssignmentForm {
} return symbolMap;
}
}

View File

@ -0,0 +1,102 @@
package dk.camelot64.kickc.icl;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
/** Helper functions for creating compiler passes */
public class PassHelper {
/**
* Replace all usages of variables in statements with aliases.
* @param aliases Variables that have alias values.
*/
public static void replace(ControlFlowGraph graph, final Map<Variable, ? extends RValue> aliases) {
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor() {
@Override
public Object visitAssignment(StatementAssignment assignment) {
if(getAlias(aliases, assignment.getLValue()) !=null) {
RValue alias = getAlias(aliases, assignment.getLValue());
if(alias instanceof LValue) {
assignment.setLValue((LValue) alias);
}
}
if(getAlias(aliases, assignment.getRValue1())!=null) {
assignment.setRValue1(getAlias(aliases, assignment.getRValue1()));
}
if(getAlias(aliases, assignment.getRValue2())!=null) {
assignment.setRValue2(getAlias(aliases, assignment.getRValue2()));
}
return null;
}
@Override
public Object visitConditionalJump(StatementConditionalJump conditionalJump) {
if(getAlias(aliases, conditionalJump.getCondition())!=null) {
conditionalJump.setCondition(getAlias(aliases, conditionalJump.getCondition()));
}
return null;
}
@Override
public Object visitPhi(StatementPhi phi) {
if(getAlias(aliases, phi.getLValue())!=null) {
RValue alias = getAlias(aliases, phi.getLValue());
if(alias instanceof LValue) {
phi.setLValue((Variable) alias);
}
}
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
if(getAlias(aliases, previousSymbol.getRValue())!=null) {
previousSymbol.setRValue(getAlias(aliases, previousSymbol.getRValue()));
}
}
return null;
}
};
visitor.visitGraph(graph);
}
/** Get the alias to use for an RValue.
*
* @param aliases The alias map
* @param rValue The RValue to find an alias for
* @return The alias to use. Null if no alias exists.
*/
private static RValue getAlias(Map<Variable, ? extends RValue> aliases,RValue rValue) {
RValue alias = aliases.get(rValue);
while (aliases.get(alias)!=null) {
alias = aliases.get(alias);
}
return alias;
}
/**
* Remove all assignments to specific LValues from the control frlo graph (as they are no longer needed).
* @param graph The control flow graph
* @param symbolTable The symbol table
* @param variables The variables to eliminate
*/
public static void removeAssignments(ControlFlowGraph graph, SymbolTable symbolTable, Collection<? extends LValue> variables) {
for (ControlFlowBlock block : graph.getAllBlocks()) {
for (Iterator<Statement> iterator = block.getStatements().iterator(); iterator.hasNext(); ) {
Statement statement = iterator.next();
if (statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
if (variables.contains(assignment.getLValue())) {
iterator.remove();
symbolTable.remove((Symbol) assignment.getLValue());
}
} else if(statement instanceof StatementPhi) {
StatementPhi phi = (StatementPhi) statement;
if (variables.contains(phi.getLValue())) {
iterator.remove();
symbolTable.remove(phi.getLValue());
}
}
}
}
}
}

View File

@ -0,0 +1,62 @@
package dk.camelot64.kickc.icl;
import java.util.HashMap;
import java.util.Map;
/** Compiler Pass eliminating redundant phi functions */
public class PassRedundantPhiElimination {
private SymbolTable symbolTable;
private ControlFlowGraph graph;
public PassRedundantPhiElimination(SymbolTable symbolTable, ControlFlowGraph graph) {
this.symbolTable = symbolTable;
this.graph = graph;
}
/**
* Eliminate alias assignments replacing them with the aliassed variable.
*/
public void eliminate() {
final Map<Variable, RValue> aliases = findRedundantPhis();
PassHelper.removeAssignments(graph, symbolTable, aliases.keySet());
PassHelper.replace(graph, aliases);
for (Variable var : aliases.keySet()) {
RValue alias = aliases.get(var);
System.out.println("Redundant Phi " + var + " " + alias);
}
}
/**
* Find phi variables where all previous symbols are identical.
* @return Map from (phi) Variable to the previous value
*/
private Map<Variable, RValue> findRedundantPhis() {
final Map<Variable, RValue> aliases = new HashMap<>();
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitPhi(StatementPhi phi) {
boolean found = true;
RValue phiRValue = null;
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
if(phiRValue==null) {
phiRValue = previousSymbol.getRValue();
} else {
if(!phiRValue.equals(previousSymbol.getRValue())) {
found = false;
break;
}
}
}
if(found) {
VariableVersion variable = phi.getLValue();
aliases.put(variable, phiRValue);
}
return null;
}
};
visitor.visitGraph(graph);
return aliases;
}
}

View File

@ -9,7 +9,7 @@ public class PassTypeInference {
for (Statement statement : sequence.getStatements()) {
if (statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
Variable symbol = (Variable) assignment.getlValue();
Variable symbol = (Variable) assignment.getLValue();
if (SymbolType.VAR.equals(symbol.getType())) {
// Unresolved symbol - perform inference
Operator operator = assignment.getOperator();

View File

@ -38,7 +38,7 @@ public class StatementAssignment implements Statement {
this.rValue2 = rValue2;
}
public LValue getlValue() {
public LValue getLValue() {
return lValue;
}

View File

@ -28,4 +28,8 @@ public class StatementConditionalJump implements Statement {
public String toString() {
return "if("+condition+") goto "+destination.getName();
}
public void setCondition(RValue condition) {
this.condition = condition;
}
}

View File

@ -14,7 +14,7 @@ public class StatementPhi implements Statement {
/** The versioned variable being assigned a value by the statement. */
private VariableVersion lValue;
/** The previous version of the symbol from predeccesor control blocks. */
/** The previous version of the rValue from predeccesor control blocks. */
private List<PreviousSymbol> previousVersions;
public StatementPhi(VariableVersion lValue) {
@ -23,33 +23,41 @@ public class StatementPhi implements Statement {
}
/**
* A previous version of the symbol that the phi function might take its value from.
* A previous version of the rValue that the phi function might take its value from.
* Which value is chosen depends on which block transition was made.
*/
public static class PreviousSymbol {
private ControlFlowBlock block;
private VariableVersion symbol;
private RValue rValue;
public PreviousSymbol(ControlFlowBlock block, VariableVersion symbol) {
public PreviousSymbol(ControlFlowBlock block, RValue rValue) {
this.block = block;
this.symbol = symbol;
this.rValue = rValue;
}
public ControlFlowBlock getBlock() {
return block;
}
public Symbol getSymbol() {
return symbol;
public RValue getRValue() {
return rValue;
}
public void setRValue(RValue RValue) {
this.rValue = RValue;
}
}
public VariableVersion getlValue() {
public VariableVersion getLValue() {
return lValue;
}
public void setLValue(Variable lValue) {
this.lValue = (VariableVersion) lValue;
}
public void addPreviousVersion(ControlFlowBlock block, VariableVersion symbol) {
previousVersions.add(new PreviousSymbol(block, symbol));
}
@ -63,7 +71,7 @@ public class StatementPhi implements Statement {
StringBuilder out = new StringBuilder();
out.append(lValue + "" + "phi(");
for (PreviousSymbol previousSymbol : previousVersions) {
out.append(" "+previousSymbol.getBlock().getLabel().getName()+"/"+previousSymbol.getSymbol().getName());
out.append(" "+previousSymbol.getBlock().getLabel().getName()+"/"+previousSymbol.getRValue());
}
out.append(" )");
return out.toString();

View File

@ -25,16 +25,25 @@ public class main {
new PassTypeInference().inferTypes(statementSequence, symbolTable);
PassGenerateControlFlowGraph passGenerateControlFlowGraph = new PassGenerateControlFlowGraph(symbolTable);
ControlFlowGraph controlFlowGraph = passGenerateControlFlowGraph.generate(statementSequence);
PassCullEmptyBlocks passCullEmptyBlocks = new PassCullEmptyBlocks(symbolTable, controlFlowGraph);
passCullEmptyBlocks.cull();
PassGenerateSingleStaticAssignmentForm passGenerateSingleStaticAssignmentForm = new PassGenerateSingleStaticAssignmentForm(
symbolTable, controlFlowGraph);
passGenerateSingleStaticAssignmentForm.generate();
PassConstantPropagation passConstantPropagation = new PassConstantPropagation(symbolTable, controlFlowGraph);
passConstantPropagation.propagateConstants();
PassAliasElimination passAliasElimination = new PassAliasElimination(symbolTable, controlFlowGraph);
passAliasElimination.eliminate();
PassRedundantPhiElimination passRedundantPhiElimination = new PassRedundantPhiElimination(symbolTable, controlFlowGraph);
passRedundantPhiElimination.eliminate();
PassCullEmptyBlocks passCullEmptyBlocks2 = new PassCullEmptyBlocks(symbolTable, controlFlowGraph);
passCullEmptyBlocks2.cull();
System.out.println("SYMBOLS");
System.out.println(symbolTable.toString());
System.out.println("PROGRAM");
System.out.println(statementSequence.toString());
System.out.println("CONTROL FLOW GRAPH");
System.out.println(controlFlowGraph.toString());
}
}

View File

@ -1,10 +1,12 @@
byte a = 0;
word b = 0;
byte d=a+b+1;
while(a<10) {
b=b+a;
if(b>10) {
b = b-10;
}
a=a+1;
byte e = d+d;
}
byte c = -a;
byte c = -d;