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

Added repeating pass 2 optimizations

This commit is contained in:
Jesper Gravgaard 2017-05-14 13:25:31 +02:00
parent b3fd0eb28c
commit c58a999a42
16 changed files with 449 additions and 300 deletions

View File

@ -6,14 +6,14 @@ import java.util.List;
import java.util.Map;
/** Pass that generates a control flow graph for the program */
public class PassGenerateControlFlowGraph {
public class Pass1GenerateControlFlowGraph {
public static final String FIRST_BLOCK_NAME = "@0";
private SymbolTable symbolTable;
private Map<Symbol, ControlFlowBlock> blocks;
private ControlFlowBlock firstBlock;
public PassGenerateControlFlowGraph(SymbolTable symbolTable) {
public Pass1GenerateControlFlowGraph(SymbolTable symbolTable) {
this.symbolTable = symbolTable;
this.blocks = new LinkedHashMap<>();
}

View File

@ -8,12 +8,12 @@ import java.util.Map;
* <p>First versions all variable assignments, then versions all variable usages and introduces necessary Phi-functions,
* <p>See https://en.wikipedia.org/wiki/Static_single_assignment_form
*/
public class PassGenerateSingleStaticAssignmentForm {
public class Pass1GenerateSingleStaticAssignmentForm {
private SymbolTable symbols;
private ControlFlowGraph controlFlowGraph;
public PassGenerateSingleStaticAssignmentForm(SymbolTable symbols, ControlFlowGraph controlFlowGraph) {
public Pass1GenerateSingleStaticAssignmentForm(SymbolTable symbols, ControlFlowGraph controlFlowGraph) {
this.symbols = symbols;
this.controlFlowGraph = controlFlowGraph;
}
@ -35,7 +35,7 @@ public class PassGenerateSingleStaticAssignmentForm {
if (statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
LValue lValue = assignment.getLValue();
if(lValue instanceof VariableUnversioned) {
if (lValue instanceof VariableUnversioned) {
// Assignment to a non-versioned non-intermediary variable
VariableUnversioned assignedSymbol = (VariableUnversioned) lValue;
VariableVersion version = symbols.createVersion(assignedSymbol);
@ -115,7 +115,7 @@ public class PassGenerateSingleStaticAssignmentForm {
/** Look through all new phi-functions and fill out their parameters.
* @return true if all phis were completely filled out.
* false if new phis were added , meaning another iteration is needed.
* false if new phis were added, meaning another iteration is needed.
* */
private boolean completePhiFunctions() {
Map<ControlFlowBlock, Map<VariableUnversioned, VariableVersion>> newPhis = new HashMap<>();
@ -128,23 +128,27 @@ public class PassGenerateSingleStaticAssignmentForm {
VariableVersion versioned = phi.getLValue();
VariableUnversioned unversioned = versioned.getVersionOf();
for (ControlFlowBlock predecessor : block.getPredecessors()) {
VariableVersion previousSymbol = symbolMap.get(predecessor.getLabel()).get(unversioned);
if (previousSymbol == null) {
// No previous symbol found in predecessor block. Look in new a phi functions.
Map<VariableUnversioned, VariableVersion> predecessorNewPhis = newPhis.get(predecessor);
if (predecessorNewPhis == null) {
predecessorNewPhis = new HashMap<>();
newPhis.put(predecessor, predecessorNewPhis);
}
previousSymbol = predecessorNewPhis.get(unversioned);
if (previousSymbol == null) {
// No previous symbol found in predecessor block. Add a new phi function to the predecessor.
previousSymbol = symbols.createVersion(unversioned);
predecessorNewPhis.put(unversioned, previousSymbol);
}
Map<VariableUnversioned, VariableVersion> predecessorMap = symbolMap.get(predecessor.getLabel());
VariableVersion previousSymbol = null;
if (predecessorMap != null) {
previousSymbol = predecessorMap.get(unversioned);
}
if (previousSymbol == null) {
// No previous symbol found in predecessor block. Look in new a phi functions.
Map<VariableUnversioned, VariableVersion> predecessorNewPhis = newPhis.get(predecessor);
if (predecessorNewPhis == null) {
predecessorNewPhis = new HashMap<>();
newPhis.put(predecessor, predecessorNewPhis);
}
previousSymbol = predecessorNewPhis.get(unversioned);
if (previousSymbol == null) {
// No previous symbol found in predecessor block. Add a new phi function to the predecessor.
previousSymbol = symbols.createVersion(unversioned);
predecessorNewPhis.put(unversioned, previousSymbol);
}
}
phi.addPreviousVersion(predecessor, previousSymbol);
}
phi.addPreviousVersion(predecessor, previousSymbol);
}
}
}
}
@ -152,13 +156,13 @@ public class PassGenerateSingleStaticAssignmentForm {
// Ads new phi functions to blocks
for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) {
Map<VariableUnversioned, VariableVersion> blockNewPhis = newPhis.get(block);
if(blockNewPhis!=null) {
if (blockNewPhis != null) {
for (VariableUnversioned symbol : blockNewPhis.keySet()) {
block.addPhiStatement(blockNewPhis.get(symbol));
}
}
}
return (newPhis.size()==0);
return (newPhis.size() == 0);
}
/**
@ -169,10 +173,10 @@ public class PassGenerateSingleStaticAssignmentForm {
Map<Label, Map<VariableUnversioned, VariableVersion>> symbolMap = new HashMap<>();
for (ControlFlowBlock block : this.controlFlowGraph.getAllBlocks()) {
for (Statement statement : block.getStatements()) {
if(statement instanceof StatementAssignment) {
if (statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
LValue lValue = assignment.getLValue();
if(lValue instanceof VariableVersion) {
if (lValue instanceof VariableVersion) {
VariableVersion versioned = (VariableVersion) lValue;
Label label = block.getLabel();
VariableUnversioned unversioned = versioned.getVersionOf();
@ -183,20 +187,21 @@ public class PassGenerateSingleStaticAssignmentForm {
}
blockMap.put(unversioned, versioned);
}
} else if(statement instanceof StatementPhi) {
} else if (statement instanceof StatementPhi) {
StatementPhi phi = (StatementPhi) statement;
VariableVersion versioned = phi.getLValue();
VariableUnversioned unversioned = versioned.getVersionOf();
Label label = block.getLabel();
Map<VariableUnversioned, VariableVersion> blockMap = symbolMap.get(label);
if(blockMap == null) {
if (blockMap == null) {
blockMap = new HashMap<>();
symbolMap.put(label, blockMap);
}
blockMap.put(unversioned, versioned);
}
}
} return symbolMap;
}
return symbolMap;
}
}

View File

@ -5,12 +5,12 @@ import dk.camelot64.kickc.parser.KickCParser;
import org.antlr.v4.runtime.tree.TerminalNode;
/** Generates program SSA form by visiting the ANTLR4 parse tree*/
public class PassGenerateStatementSequence extends KickCBaseVisitor<RValue> {
public class Pass1GenerateStatementSequence extends KickCBaseVisitor<RValue> {
private SymbolTable symbolTable;
private StatementSequence sequence;
public PassGenerateStatementSequence() {
public Pass1GenerateStatementSequence() {
this.symbolTable = new SymbolTable();
this.sequence = new StatementSequence();
}

View File

@ -4,38 +4,25 @@ import java.util.HashMap;
import java.util.Map;
/** Compiler Pass eliminating alias assignments */
public class PassAliasElimination {
public class Pass2AliasElimination extends Pass2Optimization {
private SymbolTable symbolTable;
private ControlFlowGraph graph;
public PassAliasElimination(SymbolTable symbolTable, ControlFlowGraph graph) {
this.symbolTable = symbolTable;
this.graph = graph;
public Pass2AliasElimination(ControlFlowGraph graph, SymbolTable symbolTable) {
super(graph, symbolTable);
}
/**
* Eliminate alias assignments replacing them with the aliassed variable.
*/
public void eliminate() {
@Override
public boolean optimize() {
final Map<Variable, Variable> aliases = findAliases();
PassHelper.removeAssignments(graph, symbolTable, aliases.values());
PassHelper.replace(graph, aliases);
removeAssignments(aliases.values());
replaceVariables(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);
}
return (aliases.size()>0);
}
/**
@ -71,7 +58,7 @@ public class PassAliasElimination {
return null;
}
};
visitor.visitGraph(graph);
visitor.visitGraph(getGraph());
return aliases;
}

View File

@ -4,14 +4,10 @@ import java.util.HashMap;
import java.util.Map;
/** Compiler Pass propagating constants in expressions eliminating constant variables */
public class PassConstantPropagation {
public class Pass2ConstantPropagation extends Pass2Optimization {
private SymbolTable symbolTable;
private ControlFlowGraph controlFlowGraph;
public PassConstantPropagation(SymbolTable symbolTable, ControlFlowGraph controlFlowGraph) {
this.symbolTable = symbolTable;
this.controlFlowGraph = controlFlowGraph;
public Pass2ConstantPropagation(ControlFlowGraph graph, SymbolTable symbolTable) {
super(graph, symbolTable);
}
/**
@ -19,18 +15,16 @@ public class PassConstantPropagation {
* @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);
@Override
public boolean optimize() {
final Map<Variable, Constant> constants = findConstantVariables();
for (Variable constantVar : constants.keySet()) {
Constant constantValue = constants.get(constantVar);
System.out.println("Constant " + constantVar + " " + constantValue);
}
removeAssignments(constants.keySet());
replaceVariables(constants);
return constants.size() > 0;
}
/**
@ -42,10 +36,10 @@ public class PassConstantPropagation {
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitAssignment(StatementAssignment assignment) {
if(assignment.getLValue() instanceof VariableVersion || assignment.getLValue() instanceof VariableIntermediate ) {
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) {
if (assignment.getRValue1() == null && assignment.getRValue2() instanceof Constant) {
if (assignment.getOperator() == null) {
// Constant assignment
Constant constant = (Constant) assignment.getRValue2();
constants.put(variable, constant);
@ -54,9 +48,12 @@ public class PassConstantPropagation {
Constant constant = calculateUnary(assignment.getOperator(), (Constant) assignment.getRValue2());
constants.put(variable, constant);
}
} else if(assignment.getRValue1() instanceof Constant && assignment.getRValue2() instanceof 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());
Constant constant = calculateBinary(
assignment.getOperator(),
(Constant) assignment.getRValue1(),
(Constant) assignment.getRValue2());
constants.put(variable, constant);
}
}
@ -65,9 +62,9 @@ public class PassConstantPropagation {
@Override
public Void visitPhi(StatementPhi phi) {
if(phi.getPreviousVersions().size()==1) {
if (phi.getPreviousVersions().size() == 1) {
StatementPhi.PreviousSymbol previousSymbol = phi.getPreviousVersions().get(0);
if(previousSymbol.getRValue() instanceof Constant) {
if (previousSymbol.getRValue() instanceof Constant) {
VariableVersion variable = phi.getLValue();
Constant constant = (Constant) previousSymbol.getRValue();
constants.put(variable, constant);
@ -76,68 +73,68 @@ public class PassConstantPropagation {
return null;
}
};
visitor.visitGraph(controlFlowGraph);
visitor.visitGraph(getGraph());
return constants;
}
public static Constant calculateBinary(Operator operator, Constant c1, Constant c2) {
switch(operator.getOperator()) {
switch (operator.getOperator()) {
case "-": {
if(c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
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) {
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());
throw new RuntimeException("Unhandled Binary Operator " + operator.getOperator());
}
}
private static Integer getInteger(Constant constant) {
if(constant instanceof ConstantInteger) {
if (constant instanceof ConstantInteger) {
return ((ConstantInteger) constant).getNumber();
} else {
throw new RuntimeException("Type Mismatch. Constant is not an integer number "+constant);
throw new RuntimeException("Type Mismatch. Constant is not an integer number " + constant);
}
}
private static Double getDouble(Constant constant) {
if(constant instanceof ConstantDouble) {
if (constant instanceof ConstantDouble) {
return ((ConstantDouble) constant).getNumber();
} else if(constant instanceof ConstantInteger) {
} else if (constant instanceof ConstantInteger) {
return ((ConstantInteger) constant).getNumber().doubleValue();
} else {
throw new RuntimeException("Type Mismatch. Constant is not a number "+constant);
throw new RuntimeException("Type Mismatch. Constant is not a number " + constant);
}
}
public static Constant calculateUnary(Operator operator, Constant c) {
switch(operator.getOperator()) {
switch (operator.getOperator()) {
case "-": {
if(c instanceof ConstantInteger) {
if (c instanceof ConstantInteger) {
ConstantInteger cInt = (ConstantInteger) c;
return new ConstantInteger(-cInt.getNumber());
} else if(c instanceof ConstantDouble) {
} 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);
} else {
throw new RuntimeException("Type mismatch. Unary Minus cannot handle value " + c);
}
}
case "+": {
return c;
}
default:
throw new RuntimeException("Unhandled Unary Operator "+operator.getOperator());
throw new RuntimeException("Unhandled Unary Operator " + operator.getOperator());
}
}

View File

@ -0,0 +1,49 @@
package dk.camelot64.kickc.icl;
import java.util.*;
/** Pass that culls empty control flow blocks from the program */
public class Pass2CullEmptyBlocks extends Pass2Optimization {
public Pass2CullEmptyBlocks(ControlFlowGraph graph, SymbolTable symbolTable) {
super(graph, symbolTable);
}
@Override
public boolean optimize() {
List<ControlFlowBlock> remove = new ArrayList<>();
Map<Label, Label> replace = new HashMap<>();
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
if (block.getStatements().isEmpty()) {
remove.add(block);
}
}
for (ControlFlowBlock block : remove) {
ControlFlowBlock successor = block.getDefaultSuccessor();
for (ControlFlowBlock predecessor : block.getPredecessors()) {
replace.put(block.getLabel(), predecessor.getLabel());
if (predecessor.getDefaultSuccessor().equals(block)) {
predecessor.setDefaultSuccessor(successor);
if (successor != null) {
successor.addPredecessor(predecessor);
}
}
if (predecessor.getConditionalSuccessor().equals(block)) {
predecessor.setConditionalSuccessor(successor);
if (successor != null) {
successor.addPredecessor(predecessor);
}
}
}
if (successor != null) {
successor.removePredecessor(block);
}
getGraph().getAllBlocks().remove(block);
getSymbols().remove(block.getLabel());
System.out.println("Culled Empty Block " + block.getLabel());
}
replaceLabels(replace);
return remove.size()>0;
}
}

View File

@ -0,0 +1,191 @@
package dk.camelot64.kickc.icl;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
/**
* Optimization performed during Compiler Pass 2.
* Optimizations are performed repeatedly until none of them yield any result
* */
public abstract class Pass2Optimization {
private ControlFlowGraph graph;
private SymbolTable symbolTable;
public Pass2Optimization(ControlFlowGraph graph, SymbolTable symbolTable) {
this.graph = graph;
this.symbolTable = symbolTable;
}
public ControlFlowGraph getGraph() {
return graph;
}
public SymbolTable getSymbols() {
return symbolTable;
}
/**
* Attempt to perform optimization.
*
* @return true if an optimization was performed. false if no optimization was possible.
*/
public abstract boolean optimize();
/** Singleton signalling that an RValue is never assigned and can safely be discarded as rvalue in phi-functions.*/
public static RValue VOID = new RValue() {
@Override
public String toString() {
return "VOID";
}
};
/**
* Replace all usages of variables in statements with aliases.
* @param aliases Variables that have alias values.
*/
public void replaceVariables(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 (Iterator<StatementPhi.PreviousSymbol> iterator = phi.getPreviousVersions().iterator(); iterator.hasNext(); ) {
StatementPhi.PreviousSymbol previousSymbol = iterator.next();
if (getAlias(aliases, previousSymbol.getRValue()) != null) {
RValue alias = getAlias(aliases, previousSymbol.getRValue());
if (VOID.equals(alias)) {
iterator.remove();
} else {
previousSymbol.setRValue(alias);
}
}
}
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;
}
/**
* Replace all usages of a label in statements with another label.
* @param replacements Variables that have alias values.
*/
public void replaceLabels(final Map<Label, Label> replacements) {
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor() {
@Override
public Object visitConditionalJump(StatementConditionalJump conditionalJump) {
if(getReplacement(replacements, conditionalJump.getDestination())!=null) {
conditionalJump.setDestination(getReplacement(replacements, conditionalJump.getDestination()));
}
return null;
}
@Override
public Object visitJump(StatementJump jump) {
if(getReplacement(replacements, jump.getDestination())!=null) {
jump.setDestination(getReplacement(replacements, jump.getDestination()));
}
return null;
}
@Override
public Object visitPhi(StatementPhi phi) {
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
Label replacement = getReplacement(replacements, previousSymbol.getBlock().getLabel());
if(replacement !=null) {
previousSymbol.setBlock(graph.getBlock(replacement));
}
}
return null;
}
};
visitor.visitGraph(graph);
}
/** Get the label to use as replacement for another label.
*
* @param replacements The label replacement map
* @param label The label to find a replacement for
* @return The alias to use. Null if no replacement exists.
*/
private static Label getReplacement(Map<Label, Label> replacements,Label label) {
Label replacement = replacements.get(label);
while (replacements.get(replacement)!=null) {
replacement = replacements.get(replacement);
}
return replacement;
}
/**
* Remove all assignments to specific LValues from the control frlo graph (as they are no longer needed).
* @param variables The variables to eliminate
*/
public void removeAssignments(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

@ -4,27 +4,25 @@ import java.util.HashMap;
import java.util.Map;
/** Compiler Pass eliminating redundant phi functions */
public class PassRedundantPhiElimination {
public class Pass2RedundantPhiElimination extends Pass2Optimization{
private SymbolTable symbolTable;
private ControlFlowGraph graph;
public PassRedundantPhiElimination(SymbolTable symbolTable, ControlFlowGraph graph) {
this.symbolTable = symbolTable;
this.graph = graph;
public Pass2RedundantPhiElimination(ControlFlowGraph graph, SymbolTable symbolTable) {
super(graph, symbolTable);
}
/**
* Eliminate alias assignments replacing them with the aliassed variable.
* Eliminate alias assignments replacing them with the aliased variable.
*/
public void eliminate() {
@Override
public boolean optimize() {
final Map<Variable, RValue> aliases = findRedundantPhis();
PassHelper.removeAssignments(graph, symbolTable, aliases.keySet());
PassHelper.replace(graph, aliases);
removeAssignments(aliases.keySet());
replaceVariables(aliases);
for (Variable var : aliases.keySet()) {
RValue alias = aliases.get(var);
System.out.println("Redundant Phi " + var + " " + alias);
}
return aliases.size()>0;
}
/**
@ -50,12 +48,13 @@ public class PassRedundantPhiElimination {
}
if(found) {
VariableVersion variable = phi.getLValue();
if(phiRValue==null) {phiRValue = VOID;}
aliases.put(variable, phiRValue);
}
return null;
}
};
visitor.visitGraph(graph);
visitor.visitGraph(getGraph());
return aliases;
}

View File

@ -0,0 +1,37 @@
package dk.camelot64.kickc.icl;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/** Compiler Pass eliminating phi self assignments */
public class Pass2SelfPhiElimination extends Pass2Optimization{
public Pass2SelfPhiElimination(ControlFlowGraph graph, SymbolTable symbolTable) {
super(graph, symbolTable);
}
/**
* Eliminate alias assignments replacing them with the aliased variable.
*/
@Override
public boolean optimize() {
final Boolean[] optimized = {Boolean.FALSE};
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitPhi(StatementPhi phi) {
for (Iterator<StatementPhi.PreviousSymbol> iterator = phi.getPreviousVersions().iterator(); iterator.hasNext(); ) {
StatementPhi.PreviousSymbol previousSymbol = iterator.next();
if (previousSymbol.getRValue().equals(phi.getLValue())) {
iterator.remove();
optimized[0] = Boolean.TRUE;
System.out.println("Self Phi Eliminated "+phi.getLValue());
}
}
return null;
}
};
visitor.visitGraph(getGraph());
return optimized[0];
}
}

View File

@ -1,42 +0,0 @@
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

@ -1,102 +0,0 @@
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

@ -32,4 +32,8 @@ public class StatementConditionalJump implements Statement {
public void setCondition(RValue condition) {
this.condition = condition;
}
public void setDestination(Label destination) {
this.destination = destination;
}
}

View File

@ -22,4 +22,8 @@ public class StatementJump implements Statement {
public String toString() {
return "goto "+destination.getName();
}
public void setDestination(Label destination) {
this.destination = destination;
}
}

View File

@ -47,6 +47,10 @@ public class StatementPhi implements Statement {
public void setRValue(RValue RValue) {
this.rValue = RValue;
}
public void setBlock(ControlFlowBlock block) {
this.block = block;
}
}
public VariableVersion getLValue() {

View File

@ -0,0 +1,65 @@
package dk.camelot64.kickc.test;
import dk.camelot64.kickc.icl.*;
import dk.camelot64.kickc.parser.KickCLexer;
import dk.camelot64.kickc.parser.KickCParser;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.List;
/** Test my KickC Grammar */
public class Main {
public static void main(String[] args) throws IOException {
CharStream input = CharStreams.fromFileName("src/dk/camelot64/kickc/test/test.kc");
System.out.println(input.toString());
KickCLexer lexer = new KickCLexer(input);
KickCParser parser = new KickCParser(new CommonTokenStream(lexer));
parser.setBuildParseTree(true);
KickCParser.FileContext file = parser.file();
Pass1GenerateStatementSequence pass1GenerateStatementSequence = new Pass1GenerateStatementSequence();
pass1GenerateStatementSequence.generate(file);
StatementSequence statementSequence = pass1GenerateStatementSequence.getSequence();
SymbolTable symbolTable = pass1GenerateStatementSequence.getSymbols();
new PassTypeInference().inferTypes(statementSequence, symbolTable);
System.out.println("PROGRAM");
System.out.println(statementSequence.toString());
Pass1GenerateControlFlowGraph pass1GenerateControlFlowGraph = new Pass1GenerateControlFlowGraph(symbolTable);
ControlFlowGraph controlFlowGraph = pass1GenerateControlFlowGraph.generate(statementSequence);
Pass1GenerateSingleStaticAssignmentForm pass1GenerateSingleStaticAssignmentForm =
new Pass1GenerateSingleStaticAssignmentForm(symbolTable, controlFlowGraph);
pass1GenerateSingleStaticAssignmentForm.generate();
List<Pass2Optimization> optimizations = new ArrayList<>();
optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, symbolTable));
optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, symbolTable));
optimizations.add(new Pass2AliasElimination(controlFlowGraph, symbolTable));
optimizations.add(new Pass2RedundantPhiElimination(controlFlowGraph, symbolTable));
optimizations.add(new Pass2SelfPhiElimination(controlFlowGraph, symbolTable));
boolean optimized = true;
while (optimized) {
optimized = false;
for (Pass2Optimization optimization : optimizations) {
boolean stepOptimized = optimization.optimize();
if (stepOptimized) {
System.out.println("Succesful optimization "+optimization);
optimized = true;
}
}
}
System.out.println("SYMBOLS");
System.out.println(symbolTable.toString());
System.out.println("CONTROL FLOW GRAPH");
System.out.println(controlFlowGraph.toString());
}
}

View File

@ -1,49 +0,0 @@
package dk.camelot64.kickc.test;
import dk.camelot64.kickc.icl.*;
import dk.camelot64.kickc.parser.KickCLexer;
import dk.camelot64.kickc.parser.KickCParser;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import java.io.IOException;
/** Test my KickC Grammar */
public class main {
public static void main(String [] args) throws IOException {
CharStream input = CharStreams.fromFileName("src/dk/camelot64/kickc/test/test.kc");
System.out.println(input.toString());
KickCLexer lexer = new KickCLexer(input);
KickCParser parser = new KickCParser(new CommonTokenStream(lexer));
parser.setBuildParseTree(true);
KickCParser.FileContext file = parser.file();
PassGenerateStatementSequence passGenerateStatementSequence = new PassGenerateStatementSequence();
passGenerateStatementSequence.generate(file);
StatementSequence statementSequence = passGenerateStatementSequence.getSequence();
SymbolTable symbolTable = passGenerateStatementSequence.getSymbols();
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());
}
}