mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-04-08 14:37:40 +00:00
Added more simple optimizing passes
This commit is contained in:
parent
73fa2839e0
commit
b3fd0eb28c
src/dk/camelot64/kickc
icl
Constant.javaConstantDouble.javaControlFlowGraphBaseVisitor.javaLValue.javaPassAliasElimination.javaPassConstantPropagation.javaPassCullEmptyBlocks.javaPassGenerateControlFlowGraph.javaPassGenerateSingleStaticAssignmentForm.javaPassHelper.javaPassRedundantPhiElimination.javaPassTypeInference.javaStatementAssignment.javaStatementConditionalJump.javaStatementPhi.java
test
@ -3,5 +3,4 @@ package dk.camelot64.kickc.icl;
|
||||
/** SSA form constant value */
|
||||
public interface Constant extends RValue {
|
||||
|
||||
|
||||
}
|
||||
|
@ -15,4 +15,8 @@ public class ConstantDouble implements Constant {
|
||||
public String toString() {
|
||||
return Double.toString(number);
|
||||
}
|
||||
|
||||
public Double getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
59
src/dk/camelot64/kickc/icl/ControlFlowGraphBaseVisitor.java
Normal file
59
src/dk/camelot64/kickc/icl/ControlFlowGraphBaseVisitor.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
}
|
||||
|
79
src/dk/camelot64/kickc/icl/PassAliasElimination.java
Normal file
79
src/dk/camelot64/kickc/icl/PassAliasElimination.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
144
src/dk/camelot64/kickc/icl/PassConstantPropagation.java
Normal file
144
src/dk/camelot64/kickc/icl/PassConstantPropagation.java
Normal 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
42
src/dk/camelot64/kickc/icl/PassCullEmptyBlocks.java
Normal file
42
src/dk/camelot64/kickc/icl/PassCullEmptyBlocks.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
102
src/dk/camelot64/kickc/icl/PassHelper.java
Normal file
102
src/dk/camelot64/kickc/icl/PassHelper.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
62
src/dk/camelot64/kickc/icl/PassRedundantPhiElimination.java
Normal file
62
src/dk/camelot64/kickc/icl/PassRedundantPhiElimination.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
@ -38,7 +38,7 @@ public class StatementAssignment implements Statement {
|
||||
this.rValue2 = rValue2;
|
||||
}
|
||||
|
||||
public LValue getlValue() {
|
||||
public LValue getLValue() {
|
||||
return lValue;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user