mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-10-21 02:24:34 +00:00
Added more simple optimizing passes
This commit is contained in:
parent
73fa2839e0
commit
b3fd0eb28c
@ -3,5 +3,4 @@ package dk.camelot64.kickc.icl;
|
|||||||
/** SSA form constant value */
|
/** SSA form constant value */
|
||||||
public interface Constant extends RValue {
|
public interface Constant extends RValue {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,4 +15,8 @@ public class ConstantDouble implements Constant {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return Double.toString(number);
|
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;
|
package dk.camelot64.kickc.icl;
|
||||||
|
|
||||||
/** Assignable value (capable of being on the left part of an assignment)*/
|
/** 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);
|
currentBlock.addStatement(statement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cullEmptyBlocks();
|
|
||||||
return new ControlFlowGraph(blocks, firstBlock);
|
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) {
|
private ControlFlowBlock getOrCreateBlock(Label label) {
|
||||||
ControlFlowBlock block = blocks.get(label);
|
ControlFlowBlock block = blocks.get(label);
|
||||||
if(block==null) {
|
if(block==null) {
|
||||||
|
@ -34,7 +34,7 @@ public class PassGenerateSingleStaticAssignmentForm {
|
|||||||
for (Statement statement : block.getStatements()) {
|
for (Statement statement : block.getStatements()) {
|
||||||
if (statement instanceof StatementAssignment) {
|
if (statement instanceof StatementAssignment) {
|
||||||
StatementAssignment assignment = (StatementAssignment) statement;
|
StatementAssignment assignment = (StatementAssignment) statement;
|
||||||
LValue lValue = assignment.getlValue();
|
LValue lValue = assignment.getLValue();
|
||||||
if(lValue instanceof VariableUnversioned) {
|
if(lValue instanceof VariableUnversioned) {
|
||||||
// Assignment to a non-versioned non-intermediary variable
|
// Assignment to a non-versioned non-intermediary variable
|
||||||
VariableUnversioned assignedSymbol = (VariableUnversioned) lValue;
|
VariableUnversioned assignedSymbol = (VariableUnversioned) lValue;
|
||||||
@ -69,7 +69,7 @@ public class PassGenerateSingleStaticAssignmentForm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update map of versions encountered in the block
|
// Update map of versions encountered in the block
|
||||||
LValue lValue = assignment.getlValue();
|
LValue lValue = assignment.getLValue();
|
||||||
if (lValue instanceof VariableVersion) {
|
if (lValue instanceof VariableVersion) {
|
||||||
VariableVersion versioned = (VariableVersion) lValue;
|
VariableVersion versioned = (VariableVersion) lValue;
|
||||||
blockVersions.put(versioned.getVersionOf(), versioned);
|
blockVersions.put(versioned.getVersionOf(), versioned);
|
||||||
@ -81,7 +81,6 @@ public class PassGenerateSingleStaticAssignmentForm {
|
|||||||
block.addPhiStatement(blockNewPhis.get(symbol));
|
block.addPhiStatement(blockNewPhis.get(symbol));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,7 +125,7 @@ public class PassGenerateSingleStaticAssignmentForm {
|
|||||||
if (statement instanceof StatementPhi) {
|
if (statement instanceof StatementPhi) {
|
||||||
StatementPhi phi = (StatementPhi) statement;
|
StatementPhi phi = (StatementPhi) statement;
|
||||||
if (phi.getPreviousVersions().isEmpty()) {
|
if (phi.getPreviousVersions().isEmpty()) {
|
||||||
VariableVersion versioned = phi.getlValue();
|
VariableVersion versioned = phi.getLValue();
|
||||||
VariableUnversioned unversioned = versioned.getVersionOf();
|
VariableUnversioned unversioned = versioned.getVersionOf();
|
||||||
for (ControlFlowBlock predecessor : block.getPredecessors()) {
|
for (ControlFlowBlock predecessor : block.getPredecessors()) {
|
||||||
VariableVersion previousSymbol = symbolMap.get(predecessor.getLabel()).get(unversioned);
|
VariableVersion previousSymbol = symbolMap.get(predecessor.getLabel()).get(unversioned);
|
||||||
@ -172,7 +171,7 @@ public class PassGenerateSingleStaticAssignmentForm {
|
|||||||
for (Statement statement : block.getStatements()) {
|
for (Statement statement : block.getStatements()) {
|
||||||
if(statement instanceof StatementAssignment) {
|
if(statement instanceof StatementAssignment) {
|
||||||
StatementAssignment assignment = (StatementAssignment) statement;
|
StatementAssignment assignment = (StatementAssignment) statement;
|
||||||
LValue lValue = assignment.getlValue();
|
LValue lValue = assignment.getLValue();
|
||||||
if(lValue instanceof VariableVersion) {
|
if(lValue instanceof VariableVersion) {
|
||||||
VariableVersion versioned = (VariableVersion) lValue;
|
VariableVersion versioned = (VariableVersion) lValue;
|
||||||
Label label = block.getLabel();
|
Label label = block.getLabel();
|
||||||
@ -186,7 +185,7 @@ public class PassGenerateSingleStaticAssignmentForm {
|
|||||||
}
|
}
|
||||||
} else if(statement instanceof StatementPhi) {
|
} else if(statement instanceof StatementPhi) {
|
||||||
StatementPhi phi = (StatementPhi) statement;
|
StatementPhi phi = (StatementPhi) statement;
|
||||||
VariableVersion versioned = phi.getlValue();
|
VariableVersion versioned = phi.getLValue();
|
||||||
VariableUnversioned unversioned = versioned.getVersionOf();
|
VariableUnversioned unversioned = versioned.getVersionOf();
|
||||||
Label label = block.getLabel();
|
Label label = block.getLabel();
|
||||||
Map<VariableUnversioned, VariableVersion> blockMap = symbolMap.get(label);
|
Map<VariableUnversioned, VariableVersion> blockMap = symbolMap.get(label);
|
||||||
@ -200,5 +199,4 @@ public class PassGenerateSingleStaticAssignmentForm {
|
|||||||
} return symbolMap;
|
} 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()) {
|
for (Statement statement : sequence.getStatements()) {
|
||||||
if (statement instanceof StatementAssignment) {
|
if (statement instanceof StatementAssignment) {
|
||||||
StatementAssignment assignment = (StatementAssignment) statement;
|
StatementAssignment assignment = (StatementAssignment) statement;
|
||||||
Variable symbol = (Variable) assignment.getlValue();
|
Variable symbol = (Variable) assignment.getLValue();
|
||||||
if (SymbolType.VAR.equals(symbol.getType())) {
|
if (SymbolType.VAR.equals(symbol.getType())) {
|
||||||
// Unresolved symbol - perform inference
|
// Unresolved symbol - perform inference
|
||||||
Operator operator = assignment.getOperator();
|
Operator operator = assignment.getOperator();
|
||||||
|
@ -38,7 +38,7 @@ public class StatementAssignment implements Statement {
|
|||||||
this.rValue2 = rValue2;
|
this.rValue2 = rValue2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LValue getlValue() {
|
public LValue getLValue() {
|
||||||
return lValue;
|
return lValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,4 +28,8 @@ public class StatementConditionalJump implements Statement {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "if("+condition+") goto "+destination.getName();
|
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. */
|
/** The versioned variable being assigned a value by the statement. */
|
||||||
private VariableVersion lValue;
|
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;
|
private List<PreviousSymbol> previousVersions;
|
||||||
|
|
||||||
public StatementPhi(VariableVersion lValue) {
|
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.
|
* Which value is chosen depends on which block transition was made.
|
||||||
*/
|
*/
|
||||||
public static class PreviousSymbol {
|
public static class PreviousSymbol {
|
||||||
private ControlFlowBlock block;
|
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.block = block;
|
||||||
this.symbol = symbol;
|
this.rValue = rValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControlFlowBlock getBlock() {
|
public ControlFlowBlock getBlock() {
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Symbol getSymbol() {
|
public RValue getRValue() {
|
||||||
return symbol;
|
return rValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setRValue(RValue RValue) {
|
||||||
|
this.rValue = RValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public VariableVersion getlValue() {
|
public VariableVersion getLValue() {
|
||||||
return lValue;
|
return lValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLValue(Variable lValue) {
|
||||||
|
this.lValue = (VariableVersion) lValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addPreviousVersion(ControlFlowBlock block, VariableVersion symbol) {
|
public void addPreviousVersion(ControlFlowBlock block, VariableVersion symbol) {
|
||||||
previousVersions.add(new PreviousSymbol(block, symbol));
|
previousVersions.add(new PreviousSymbol(block, symbol));
|
||||||
}
|
}
|
||||||
@ -63,7 +71,7 @@ public class StatementPhi implements Statement {
|
|||||||
StringBuilder out = new StringBuilder();
|
StringBuilder out = new StringBuilder();
|
||||||
out.append(lValue + " ← " + "phi(");
|
out.append(lValue + " ← " + "phi(");
|
||||||
for (PreviousSymbol previousSymbol : previousVersions) {
|
for (PreviousSymbol previousSymbol : previousVersions) {
|
||||||
out.append(" "+previousSymbol.getBlock().getLabel().getName()+"/"+previousSymbol.getSymbol().getName());
|
out.append(" "+previousSymbol.getBlock().getLabel().getName()+"/"+previousSymbol.getRValue());
|
||||||
}
|
}
|
||||||
out.append(" )");
|
out.append(" )");
|
||||||
return out.toString();
|
return out.toString();
|
||||||
|
@ -25,16 +25,25 @@ public class main {
|
|||||||
new PassTypeInference().inferTypes(statementSequence, symbolTable);
|
new PassTypeInference().inferTypes(statementSequence, symbolTable);
|
||||||
PassGenerateControlFlowGraph passGenerateControlFlowGraph = new PassGenerateControlFlowGraph(symbolTable);
|
PassGenerateControlFlowGraph passGenerateControlFlowGraph = new PassGenerateControlFlowGraph(symbolTable);
|
||||||
ControlFlowGraph controlFlowGraph = passGenerateControlFlowGraph.generate(statementSequence);
|
ControlFlowGraph controlFlowGraph = passGenerateControlFlowGraph.generate(statementSequence);
|
||||||
|
PassCullEmptyBlocks passCullEmptyBlocks = new PassCullEmptyBlocks(symbolTable, controlFlowGraph);
|
||||||
|
passCullEmptyBlocks.cull();
|
||||||
PassGenerateSingleStaticAssignmentForm passGenerateSingleStaticAssignmentForm = new PassGenerateSingleStaticAssignmentForm(
|
PassGenerateSingleStaticAssignmentForm passGenerateSingleStaticAssignmentForm = new PassGenerateSingleStaticAssignmentForm(
|
||||||
symbolTable, controlFlowGraph);
|
symbolTable, controlFlowGraph);
|
||||||
passGenerateSingleStaticAssignmentForm.generate();
|
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("SYMBOLS");
|
||||||
System.out.println(symbolTable.toString());
|
System.out.println(symbolTable.toString());
|
||||||
System.out.println("PROGRAM");
|
System.out.println("PROGRAM");
|
||||||
System.out.println(statementSequence.toString());
|
System.out.println(statementSequence.toString());
|
||||||
System.out.println("CONTROL FLOW GRAPH");
|
System.out.println("CONTROL FLOW GRAPH");
|
||||||
System.out.println(controlFlowGraph.toString());
|
System.out.println(controlFlowGraph.toString());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
byte a = 0;
|
byte a = 0;
|
||||||
word b = 0;
|
word b = 0;
|
||||||
|
byte d=a+b+1;
|
||||||
while(a<10) {
|
while(a<10) {
|
||||||
b=b+a;
|
b=b+a;
|
||||||
if(b>10) {
|
if(b>10) {
|
||||||
b = b-10;
|
b = b-10;
|
||||||
}
|
}
|
||||||
a=a+1;
|
a=a+1;
|
||||||
|
byte e = d+d;
|
||||||
}
|
}
|
||||||
byte c = -a;
|
byte c = -d;
|
||||||
|
Loading…
Reference in New Issue
Block a user