mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-22 13:29:18 +00:00
Added repeating pass 2 optimizations
This commit is contained in:
parent
b3fd0eb28c
commit
c58a999a42
@ -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<>();
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
49
src/dk/camelot64/kickc/icl/Pass2CullEmptyBlocks.java
Normal file
49
src/dk/camelot64/kickc/icl/Pass2CullEmptyBlocks.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
191
src/dk/camelot64/kickc/icl/Pass2Optimization.java
Normal file
191
src/dk/camelot64/kickc/icl/Pass2Optimization.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
37
src/dk/camelot64/kickc/icl/Pass2SelfPhiElimination.java
Normal file
37
src/dk/camelot64/kickc/icl/Pass2SelfPhiElimination.java
Normal 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];
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -22,4 +22,8 @@ public class StatementJump implements Statement {
|
||||
public String toString() {
|
||||
return "goto "+destination.getName();
|
||||
}
|
||||
|
||||
public void setDestination(Label destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
65
src/dk/camelot64/kickc/test/Main.java
Normal file
65
src/dk/camelot64/kickc/test/Main.java
Normal 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());
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user