From c58a999a4283a1561fbf13066cf660a097f23075 Mon Sep 17 00:00:00 2001 From: Jesper Gravgaard Date: Sun, 14 May 2017 13:25:31 +0200 Subject: [PATCH] Added repeating pass 2 optimizations --- ...ava => Pass1GenerateControlFlowGraph.java} | 4 +- ...s1GenerateSingleStaticAssignmentForm.java} | 59 +++--- ...va => Pass1GenerateStatementSequence.java} | 4 +- ...nation.java => Pass2AliasElimination.java} | 31 +-- ...ion.java => Pass2ConstantPropagation.java} | 81 ++++---- .../kickc/icl/Pass2CullEmptyBlocks.java | 49 +++++ .../kickc/icl/Pass2Optimization.java | 191 ++++++++++++++++++ ...java => Pass2RedundantPhiElimination.java} | 23 +-- .../kickc/icl/Pass2SelfPhiElimination.java | 37 ++++ .../kickc/icl/PassCullEmptyBlocks.java | 42 ---- src/dk/camelot64/kickc/icl/PassHelper.java | 102 ---------- .../kickc/icl/StatementConditionalJump.java | 4 + src/dk/camelot64/kickc/icl/StatementJump.java | 4 + src/dk/camelot64/kickc/icl/StatementPhi.java | 4 + src/dk/camelot64/kickc/test/Main.java | 65 ++++++ src/dk/camelot64/kickc/test/main.java | 49 ----- 16 files changed, 449 insertions(+), 300 deletions(-) rename src/dk/camelot64/kickc/icl/{PassGenerateControlFlowGraph.java => Pass1GenerateControlFlowGraph.java} (95%) rename src/dk/camelot64/kickc/icl/{PassGenerateSingleStaticAssignmentForm.java => Pass1GenerateSingleStaticAssignmentForm.java} (80%) rename src/dk/camelot64/kickc/icl/{PassGenerateStatementSequence.java => Pass1GenerateStatementSequence.java} (98%) rename src/dk/camelot64/kickc/icl/{PassAliasElimination.java => Pass2AliasElimination.java} (70%) rename src/dk/camelot64/kickc/icl/{PassConstantPropagation.java => Pass2ConstantPropagation.java} (62%) create mode 100644 src/dk/camelot64/kickc/icl/Pass2CullEmptyBlocks.java create mode 100644 src/dk/camelot64/kickc/icl/Pass2Optimization.java rename src/dk/camelot64/kickc/icl/{PassRedundantPhiElimination.java => Pass2RedundantPhiElimination.java} (74%) create mode 100644 src/dk/camelot64/kickc/icl/Pass2SelfPhiElimination.java delete mode 100644 src/dk/camelot64/kickc/icl/PassCullEmptyBlocks.java delete mode 100644 src/dk/camelot64/kickc/icl/PassHelper.java create mode 100644 src/dk/camelot64/kickc/test/Main.java delete mode 100644 src/dk/camelot64/kickc/test/main.java diff --git a/src/dk/camelot64/kickc/icl/PassGenerateControlFlowGraph.java b/src/dk/camelot64/kickc/icl/Pass1GenerateControlFlowGraph.java similarity index 95% rename from src/dk/camelot64/kickc/icl/PassGenerateControlFlowGraph.java rename to src/dk/camelot64/kickc/icl/Pass1GenerateControlFlowGraph.java index 4ae903793..cce903fc4 100644 --- a/src/dk/camelot64/kickc/icl/PassGenerateControlFlowGraph.java +++ b/src/dk/camelot64/kickc/icl/Pass1GenerateControlFlowGraph.java @@ -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 blocks; private ControlFlowBlock firstBlock; - public PassGenerateControlFlowGraph(SymbolTable symbolTable) { + public Pass1GenerateControlFlowGraph(SymbolTable symbolTable) { this.symbolTable = symbolTable; this.blocks = new LinkedHashMap<>(); } diff --git a/src/dk/camelot64/kickc/icl/PassGenerateSingleStaticAssignmentForm.java b/src/dk/camelot64/kickc/icl/Pass1GenerateSingleStaticAssignmentForm.java similarity index 80% rename from src/dk/camelot64/kickc/icl/PassGenerateSingleStaticAssignmentForm.java rename to src/dk/camelot64/kickc/icl/Pass1GenerateSingleStaticAssignmentForm.java index bc5f8fc36..d3b48000b 100644 --- a/src/dk/camelot64/kickc/icl/PassGenerateSingleStaticAssignmentForm.java +++ b/src/dk/camelot64/kickc/icl/Pass1GenerateSingleStaticAssignmentForm.java @@ -8,12 +8,12 @@ import java.util.Map; *

First versions all variable assignments, then versions all variable usages and introduces necessary Phi-functions, *

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> 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 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 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 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 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> 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 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; } } diff --git a/src/dk/camelot64/kickc/icl/PassGenerateStatementSequence.java b/src/dk/camelot64/kickc/icl/Pass1GenerateStatementSequence.java similarity index 98% rename from src/dk/camelot64/kickc/icl/PassGenerateStatementSequence.java rename to src/dk/camelot64/kickc/icl/Pass1GenerateStatementSequence.java index 08b84dde6..41bc59f0e 100644 --- a/src/dk/camelot64/kickc/icl/PassGenerateStatementSequence.java +++ b/src/dk/camelot64/kickc/icl/Pass1GenerateStatementSequence.java @@ -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 { +public class Pass1GenerateStatementSequence extends KickCBaseVisitor { private SymbolTable symbolTable; private StatementSequence sequence; - public PassGenerateStatementSequence() { + public Pass1GenerateStatementSequence() { this.symbolTable = new SymbolTable(); this.sequence = new StatementSequence(); } diff --git a/src/dk/camelot64/kickc/icl/PassAliasElimination.java b/src/dk/camelot64/kickc/icl/Pass2AliasElimination.java similarity index 70% rename from src/dk/camelot64/kickc/icl/PassAliasElimination.java rename to src/dk/camelot64/kickc/icl/Pass2AliasElimination.java index 804276023..24f802797 100644 --- a/src/dk/camelot64/kickc/icl/PassAliasElimination.java +++ b/src/dk/camelot64/kickc/icl/Pass2AliasElimination.java @@ -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 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 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; } diff --git a/src/dk/camelot64/kickc/icl/PassConstantPropagation.java b/src/dk/camelot64/kickc/icl/Pass2ConstantPropagation.java similarity index 62% rename from src/dk/camelot64/kickc/icl/PassConstantPropagation.java rename to src/dk/camelot64/kickc/icl/Pass2ConstantPropagation.java index aeb442b4a..6cba75b7d 100644 --- a/src/dk/camelot64/kickc/icl/PassConstantPropagation.java +++ b/src/dk/camelot64/kickc/icl/Pass2ConstantPropagation.java @@ -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 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 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 visitor = new ControlFlowGraphBaseVisitor() { @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()); } } diff --git a/src/dk/camelot64/kickc/icl/Pass2CullEmptyBlocks.java b/src/dk/camelot64/kickc/icl/Pass2CullEmptyBlocks.java new file mode 100644 index 000000000..8b6d5cef0 --- /dev/null +++ b/src/dk/camelot64/kickc/icl/Pass2CullEmptyBlocks.java @@ -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 remove = new ArrayList<>(); + Map 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; + } + +} diff --git a/src/dk/camelot64/kickc/icl/Pass2Optimization.java b/src/dk/camelot64/kickc/icl/Pass2Optimization.java new file mode 100644 index 000000000..15cc1ef34 --- /dev/null +++ b/src/dk/camelot64/kickc/icl/Pass2Optimization.java @@ -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 aliases) { + ControlFlowGraphBaseVisitor 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 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 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 replacements) { + ControlFlowGraphBaseVisitor 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 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 variables) { + for (ControlFlowBlock block : graph.getAllBlocks()) { + for (Iterator 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()); + } + } + } + } + } + +} diff --git a/src/dk/camelot64/kickc/icl/PassRedundantPhiElimination.java b/src/dk/camelot64/kickc/icl/Pass2RedundantPhiElimination.java similarity index 74% rename from src/dk/camelot64/kickc/icl/PassRedundantPhiElimination.java rename to src/dk/camelot64/kickc/icl/Pass2RedundantPhiElimination.java index 2a59d5623..65c5adc0a 100644 --- a/src/dk/camelot64/kickc/icl/PassRedundantPhiElimination.java +++ b/src/dk/camelot64/kickc/icl/Pass2RedundantPhiElimination.java @@ -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 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; } diff --git a/src/dk/camelot64/kickc/icl/Pass2SelfPhiElimination.java b/src/dk/camelot64/kickc/icl/Pass2SelfPhiElimination.java new file mode 100644 index 000000000..08c342979 --- /dev/null +++ b/src/dk/camelot64/kickc/icl/Pass2SelfPhiElimination.java @@ -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 visitor = new ControlFlowGraphBaseVisitor() { + @Override + public Void visitPhi(StatementPhi phi) { + for (Iterator 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]; + } +} diff --git a/src/dk/camelot64/kickc/icl/PassCullEmptyBlocks.java b/src/dk/camelot64/kickc/icl/PassCullEmptyBlocks.java deleted file mode 100644 index 4e0c1c0c8..000000000 --- a/src/dk/camelot64/kickc/icl/PassCullEmptyBlocks.java +++ /dev/null @@ -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 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()); - } - } - } - -} diff --git a/src/dk/camelot64/kickc/icl/PassHelper.java b/src/dk/camelot64/kickc/icl/PassHelper.java deleted file mode 100644 index c7cd061c6..000000000 --- a/src/dk/camelot64/kickc/icl/PassHelper.java +++ /dev/null @@ -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 aliases) { - ControlFlowGraphBaseVisitor 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 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 variables) { - for (ControlFlowBlock block : graph.getAllBlocks()) { - for (Iterator 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()); - } - } - } - } - } - - -} diff --git a/src/dk/camelot64/kickc/icl/StatementConditionalJump.java b/src/dk/camelot64/kickc/icl/StatementConditionalJump.java index ffc8b69e0..5e903606b 100644 --- a/src/dk/camelot64/kickc/icl/StatementConditionalJump.java +++ b/src/dk/camelot64/kickc/icl/StatementConditionalJump.java @@ -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; + } } diff --git a/src/dk/camelot64/kickc/icl/StatementJump.java b/src/dk/camelot64/kickc/icl/StatementJump.java index 4544ca416..d999bad35 100644 --- a/src/dk/camelot64/kickc/icl/StatementJump.java +++ b/src/dk/camelot64/kickc/icl/StatementJump.java @@ -22,4 +22,8 @@ public class StatementJump implements Statement { public String toString() { return "goto "+destination.getName(); } + + public void setDestination(Label destination) { + this.destination = destination; + } } diff --git a/src/dk/camelot64/kickc/icl/StatementPhi.java b/src/dk/camelot64/kickc/icl/StatementPhi.java index 8d24bddfb..abcf4678a 100644 --- a/src/dk/camelot64/kickc/icl/StatementPhi.java +++ b/src/dk/camelot64/kickc/icl/StatementPhi.java @@ -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() { diff --git a/src/dk/camelot64/kickc/test/Main.java b/src/dk/camelot64/kickc/test/Main.java new file mode 100644 index 000000000..88e3ab2ac --- /dev/null +++ b/src/dk/camelot64/kickc/test/Main.java @@ -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 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()); + } + +} diff --git a/src/dk/camelot64/kickc/test/main.java b/src/dk/camelot64/kickc/test/main.java deleted file mode 100644 index 7ab72e3e4..000000000 --- a/src/dk/camelot64/kickc/test/main.java +++ /dev/null @@ -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()); - } - -}