diff --git a/src/dk/camelot64/kickc/asm/fragment/aby=aby_plus_1.asm b/src/dk/camelot64/kickc/asm/fragment/aby=aby_plus_1.asm new file mode 100644 index 000000000..46f7e9c4b --- /dev/null +++ b/src/dk/camelot64/kickc/asm/fragment/aby=aby_plus_1.asm @@ -0,0 +1,2 @@ +clc +adc #1 \ No newline at end of file diff --git a/src/dk/camelot64/kickc/asm/fragment/aby=zpby1.asm b/src/dk/camelot64/kickc/asm/fragment/aby=zpby1.asm new file mode 100644 index 000000000..842072690 --- /dev/null +++ b/src/dk/camelot64/kickc/asm/fragment/aby=zpby1.asm @@ -0,0 +1 @@ +lda {zpby1} \ No newline at end of file diff --git a/src/dk/camelot64/kickc/asm/fragment/zpby1=aby_plus_1.asm b/src/dk/camelot64/kickc/asm/fragment/zpby1=aby_plus_1.asm new file mode 100644 index 000000000..9e229ecea --- /dev/null +++ b/src/dk/camelot64/kickc/asm/fragment/zpby1=aby_plus_1.asm @@ -0,0 +1,3 @@ +clc +adc #1 +sta {zpby1} \ No newline at end of file diff --git a/src/dk/camelot64/kickc/icl/Label.java b/src/dk/camelot64/kickc/icl/Label.java index 142c2fd9b..5baa650bc 100644 --- a/src/dk/camelot64/kickc/icl/Label.java +++ b/src/dk/camelot64/kickc/icl/Label.java @@ -26,6 +26,15 @@ public class Label implements Symbol { return scope; } + @Override + public int getScopeDepth() { + if(scope==null) { + return 0; + } else { + return scope.getScopeDepth()+1; + } + } + @Override public String getFullName() { return Scope.getFullName(this); diff --git a/src/dk/camelot64/kickc/icl/Pass1GenerateSingleStaticAssignmentForm.java b/src/dk/camelot64/kickc/icl/Pass1GenerateSingleStaticAssignmentForm.java index e5d821b76..00341f068 100644 --- a/src/dk/camelot64/kickc/icl/Pass1GenerateSingleStaticAssignmentForm.java +++ b/src/dk/camelot64/kickc/icl/Pass1GenerateSingleStaticAssignmentForm.java @@ -40,7 +40,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { if (lValue instanceof VariableUnversioned) { // Assignment to a non-versioned non-intermediary variable VariableUnversioned assignedSymbol = (VariableUnversioned) lValue; - VariableVersion version = symbols.createVersion(assignedSymbol); + VariableVersion version = assignedSymbol.createVersion(); assignment.setLValue(version); } } else if(statement instanceof StatementCall) { @@ -49,7 +49,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { if (lValue instanceof VariableUnversioned) { // Assignment to a non-versioned non-intermediary variable VariableUnversioned assignedSymbol = (VariableUnversioned) lValue; - VariableVersion version = symbols.createVersion(assignedSymbol); + VariableVersion version = assignedSymbol.createVersion(); call.setLValue(version); } } @@ -149,7 +149,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { } if (version == null) { // create a new phi function - version = symbols.createVersion(rSymbol); + version = rSymbol.createVersion(); blockNewPhis.put(rSymbol, version); } } @@ -189,7 +189,7 @@ public class Pass1GenerateSingleStaticAssignmentForm { 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); + previousSymbol = unversioned.createVersion(); predecessorNewPhis.put(unversioned, previousSymbol); } } diff --git a/src/dk/camelot64/kickc/icl/Pass2AliasElimination.java b/src/dk/camelot64/kickc/icl/Pass2AliasElimination.java index d076ad094..b011f39d7 100644 --- a/src/dk/camelot64/kickc/icl/Pass2AliasElimination.java +++ b/src/dk/camelot64/kickc/icl/Pass2AliasElimination.java @@ -2,7 +2,9 @@ package dk.camelot64.kickc.icl; import java.util.*; -/** Compiler Pass eliminating alias assignments */ +/** + * Compiler Pass eliminating alias assignments + */ public class Pass2AliasElimination extends Pass2SsaOptimization { public Pass2AliasElimination(ControlFlowGraph graph, Scope scope) { @@ -16,50 +18,77 @@ public class Pass2AliasElimination extends Pass2SsaOptimization { @Override public boolean optimize() { final Aliases aliases = findAliases(); - removeAssignments(aliases.getAssignmentsToRemove()); + removeAliasAssignments(aliases); replaceVariables(aliases.getReplacements()); deleteSymbols(aliases.getSymbolsToRemove()); - for (Alias alias : aliases.getAliases()) { - System.out.println("Alias " + alias.getKeep() + " " + alias.getEliminate()); + for (AliasSet aliasSet : aliases.getAliasSets()) { + StringBuilder str = new StringBuilder(); + str.append(aliasSet.getKeepVar()); + str.append(" = "); + for (Variable var : aliasSet.getEliminateVars()) { + str.append(var + " "); + } + System.out.println("Alias " + str); } - return (aliases.size()>0); + return (aliases.size() > 0); } - private static class Aliases { - private List aliases; + /** + * Remove all assignments that just assign an alias to itself + * + * @param aliases The aliases + */ + + private void removeAliasAssignments(Aliases aliases) { + for (ControlFlowBlock block : getGraph().getAllBlocks()) { + for (Iterator iterator = block.getStatements().iterator(); iterator.hasNext(); ) { + Statement statement = iterator.next(); + if (statement instanceof StatementAssignment) { + StatementAssignment assignment = (StatementAssignment) statement; + AliasSet aliasSet = aliases.findAliasSet(assignment.getLValue()); + if (aliasSet != null) { + if ((assignment.getRValue1() == null) && (assignment.getOperator() == null) && aliasSet.contains(assignment.getRValue2())) { + iterator.remove(); + } + } + } else if (statement instanceof StatementPhi) { + StatementPhi phi = (StatementPhi) statement; + AliasSet aliasSet = aliases.findAliasSet(phi.getLValue()); + if (aliasSet != null) { + if (phi.getPreviousVersions().size() == 1 && aliasSet.contains(phi.getPreviousVersion(0).getRValue())) { + iterator.remove(); + } + } + } + } + } + } + + public static class Aliases { + + private List aliases; public Aliases() { this.aliases = new ArrayList<>(); } - public List getAliases() { - return aliases; - } - - public List getAssignmentsToRemove() { - ArrayList eliminates = new ArrayList<>(); - for (Alias alias : aliases) { - if(alias.isKeepHasDefinition()) { - eliminates.add(alias.getEliminate()); - } else { - eliminates.add(alias.getKeep()); - } - } - return eliminates; - } - public List getSymbolsToRemove() { ArrayList eliminates = new ArrayList<>(); - for (Alias alias : aliases) { - eliminates.add(alias.getEliminate()); + for (AliasSet alias : aliases) { + eliminates.addAll(alias.getEliminateVars()); } return eliminates; } public Map getReplacements() { HashMap replacements = new HashMap<>(); - for (Alias alias : aliases) { - replacements.put(alias.getEliminate(), alias.getKeep()); + for (AliasSet aliasSet : aliases) { + Variable keepVar = aliasSet.getKeepVar(); + for (Variable var : aliasSet.getEliminateVars()) { + if(!var.equals(keepVar)) { + replacements.put(var, keepVar); + } + } } return replacements; } @@ -68,42 +97,111 @@ public class Pass2AliasElimination extends Pass2SsaOptimization { return aliases.size(); } - public void add(Variable lValue, Variable rValue) { - if(lValue instanceof VariableVersion && rValue instanceof VariableIntermediate) { - aliases.add(new Alias(lValue, rValue, false)); + public void add(Variable var1, Variable var2) { + AliasSet aliasSet1 = findAliasSet(var1); + AliasSet aliasSet2 = findAliasSet(var2); + if (aliasSet1 != null) { + if (aliasSet2 != null) { + aliasSet1.addAll(aliasSet2); + aliases.remove(aliasSet2); + } else { + aliasSet1.add(var2); + } } else { - aliases.add(new Alias(rValue, lValue, true)); + if (aliasSet2 != null) { + aliasSet2.add(var1); + } else { + AliasSet newSet = new AliasSet(); + newSet.add(var1); + newSet.add(var2); + aliases.add(newSet); + } + } + } + + public AliasSet findAliasSet(LValue lValue) { + if (lValue instanceof Variable) { + for (AliasSet alias : aliases) { + if (alias.contains(lValue)) { + return alias; + } + } + } + return null; + } + + public List getAliasSets() { + return aliases; + } + } + + public static class AliasSet { + + private List vars; + + public AliasSet() { + this.vars = new ArrayList<>(); + } + + public void add(Variable variable) { + vars.add(variable); + } + + public boolean contains(RValue rValue) { + if (rValue instanceof Variable) { + return vars.contains(rValue); + } else { + return false; + } + } + + public List getVars() { + return vars; + } + + public void addAll(AliasSet aliasSet) { + vars.addAll(aliasSet.getVars()); + } + + public Variable getKeepVar() { + Variable keep = null; + for (Variable var : vars) { + if (keep == null) { + keep = var; + } else { + if (var instanceof VariableVersion) { + if (keep instanceof VariableVersion) { + if (var.getScopeDepth() < keep.getScopeDepth()) { + keep = var; + } + } else { + keep = var; + } + } + } + } + return keep; + } + + public List getEliminateVars() { + List eliminate = new ArrayList<>(); + Variable keepVar = getKeepVar(); + for (Variable var : vars) { + if(!var.equals(keepVar)) { + eliminate.add(var); + } + } + return eliminate; + } + + public void remove(RValue rValue) { + if(rValue instanceof Variable) { + vars.remove(rValue); } } } - private static class Alias { - private Variable keep; - private Variable eliminate; - // true if the symbol to keep has the proper definition of the value. - private boolean keepHasDefinition; - - public Alias(Variable keep, Variable eliminate, boolean keepHasDefinition) { - this.keep = keep; - this.eliminate = eliminate; - this.keepHasDefinition = keepHasDefinition; - } - - public Variable getEliminate() { - return eliminate; - } - - public Variable getKeep() { - return keep; - } - - public boolean isKeepHasDefinition() { - return keepHasDefinition; - } - } - - private Aliases findAliases() { Aliases candidates = findAliasesCandidates(); @@ -113,41 +211,42 @@ public class Pass2AliasElimination extends Pass2SsaOptimization { // Remove all candidates that are used after assignment in phi blocks private void cleanupCandidates(Aliases candidates) { - Iterator candidateIt = candidates.getAliases().iterator(); - while (candidateIt.hasNext()) { - Alias candidate = candidateIt.next(); - final Variable varEliminate = candidate.getEliminate(); - final Variable varKeep = candidate.getKeep(); - final Boolean[] rMatch = {false}; + for (final AliasSet aliasSet : candidates.aliases) { final Boolean[] lMatch = {false}; ControlFlowGraphBaseVisitor candidateEliminator = new ControlFlowGraphBaseVisitor() { + @Override + public Void visitBlock(ControlFlowBlock block) { + lMatch[0] = false; + return super.visitBlock(block); + } @Override public Void visitPhi(StatementPhi phi) { - for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) { - if (previousSymbol.getRValue().equals(varKeep)) { - rMatch[0] = true; - break; + if(lMatch[0]) { + for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) { + RValue phiRValue = previousSymbol.getRValue(); + if (aliasSet.contains(phiRValue)) { + System.out.println("Alias candidate removed " + phiRValue); + aliasSet.remove(phiRValue); + break; + } } } - if (phi.getLValue().equals(varEliminate)) { + if (aliasSet.contains(phi.getLValue())) { lMatch[0] = true; } return null; } }; candidateEliminator.visitGraph(getGraph()); - if (rMatch[0] && lMatch[0]) { - System.out.println("Alias candidate removed " + varEliminate + " " + varKeep); - candidateIt.remove(); - } } } /** * Find variables that have constant values. + * * @return Map from Variable to the Constant value */ - private Aliases findAliasesCandidates() { + private Aliases findAliasesCandidates() { final Aliases aliases = new Aliases(); ControlFlowGraphBaseVisitor visitor = new ControlFlowGraphBaseVisitor() { @Override @@ -165,9 +264,9 @@ public class Pass2AliasElimination extends Pass2SsaOptimization { @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 Variable) { + if (previousSymbol.getRValue() instanceof Variable) { VariableVersion variable = phi.getLValue(); Variable alias = (Variable) previousSymbol.getRValue(); aliases.add(variable, alias); diff --git a/src/dk/camelot64/kickc/icl/Pass2SsaOptimization.java b/src/dk/camelot64/kickc/icl/Pass2SsaOptimization.java index 1a9a8261c..fcd4ac67e 100644 --- a/src/dk/camelot64/kickc/icl/Pass2SsaOptimization.java +++ b/src/dk/camelot64/kickc/icl/Pass2SsaOptimization.java @@ -106,14 +106,23 @@ public abstract class Pass2SsaOptimization { if (getAlias(aliases, aReturn.getValue()) != null) { aReturn.setValue(getAlias(aliases, aReturn.getValue())); } + return null; } @Override - public Void visitCallLValue(StatementCallLValue callLValue) { - - for (RValue parameter: callLValue.getParameters()) { - + public Void visitCallLValue(StatementCall call) { + if(call.getParameters()!=null) { + List newParams = new ArrayList<>(); + for (RValue parameter : call.getParameters()) { + RValue newParam = parameter; + if (getAlias(aliases, parameter) != null) { + newParam = getAlias(aliases, parameter); + } + newParams.add(newParam); + } + call.setParameters(newParams); } + return null; } @Override diff --git a/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java b/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java index 75e6dace1..f0aa11a7b 100644 --- a/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java +++ b/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java @@ -71,7 +71,10 @@ public class Pass3RegisterAllocation { allocation.allocate(symbols.getVariable("$4"), new RegisterAllocation.RegisterAByte()); allocation.allocate(symbols.getVariable("$6"), new RegisterAllocation.RegisterALUByte()); allocation.allocate(symbols.getVariable("$7"), new RegisterAllocation.RegisterAByte()); + allocation.allocate(symbols.getVariable("inc::a#2"), new RegisterAllocation.RegisterAByte()); + allocation.allocate(symbols.getVariable("bv#0"), new RegisterAllocation.RegisterAByte()); symbols.setAllocation(allocation); + } } diff --git a/src/dk/camelot64/kickc/icl/Scope.java b/src/dk/camelot64/kickc/icl/Scope.java index ee783cd37..b9d9d5482 100644 --- a/src/dk/camelot64/kickc/icl/Scope.java +++ b/src/dk/camelot64/kickc/icl/Scope.java @@ -40,10 +40,10 @@ public class Scope implements Symbol { } public static String getFullName(Symbol symbol) { - if(symbol.getScope()!=null) { + if (symbol.getScope() != null) { String scopeName = symbol.getScope().getFullName(); - if(scopeName.length()>0) { - return scopeName+"::"+symbol.getLocalName(); + if (scopeName.length() > 0) { + return scopeName + "::" + symbol.getLocalName(); } } return symbol.getLocalName(); @@ -65,6 +65,15 @@ public class Scope implements Symbol { return type; } + @Override + public int getScopeDepth() { + if (parentScope == null) { + return 0; + } else { + return parentScope.getScopeDepth() + 1; + } + } + public Symbol add(Symbol symbol) { if (symbols.get(symbol.getLocalName()) != null) { throw new RuntimeException("Symbol already declared " + symbol.getLocalName()); @@ -90,10 +99,28 @@ public class Scope implements Symbol { return symbol; } - public Variable getVariable(String name) { - return (Variable) symbols.get(name); + public Symbol getSymbol(String name) { + int pos = name.indexOf("::"); + if (pos >= 0) { + String scopeName = name.substring(0, pos); + String rest = name.substring(pos + 2); + Symbol scopeSym = symbols.get(scopeName); + if (scopeSym instanceof Scope) { + return ((Scope) scopeSym).getSymbol(rest); + } else { + throw new RuntimeException("Error looking up symbol " + name); + } + } else { + return symbols.get(name); + } } + + public Variable getVariable(String name) { + return (Variable) getSymbol(name); + } + + public Collection getAllVariables() { Collection vars = new ArrayList<>(); for (Symbol symbol : symbols.values()) { @@ -140,14 +167,13 @@ public class Scope implements Symbol { } } - public VariableVersion createVersion(VariableUnversioned symbol) { - VariableVersion version = new VariableVersion(symbol, symbol.getNextVersionNumber()); - symbols.put(version.getLocalName(), version); - return version; - } - public void setAllocation(RegisterAllocation allocation) { this.allocation = allocation; + for (Symbol symbol : symbols.values()) { + if(symbol instanceof Scope) { + ((Scope) symbol).setAllocation(allocation); + } + } } public RegisterAllocation.Register getRegister(Variable variable) { diff --git a/src/dk/camelot64/kickc/icl/StatementCall.java b/src/dk/camelot64/kickc/icl/StatementCall.java index 327528f90..650fd6be5 100644 --- a/src/dk/camelot64/kickc/icl/StatementCall.java +++ b/src/dk/camelot64/kickc/icl/StatementCall.java @@ -47,6 +47,10 @@ public class StatementCall implements StatementLValue { return parameters; } + public void setParameters(List parameters) { + this.parameters = parameters; + } + public int getNumParameters() { return parameters.size(); } diff --git a/src/dk/camelot64/kickc/icl/StatementPhi.java b/src/dk/camelot64/kickc/icl/StatementPhi.java index 559e0e9d0..0e53362b0 100644 --- a/src/dk/camelot64/kickc/icl/StatementPhi.java +++ b/src/dk/camelot64/kickc/icl/StatementPhi.java @@ -22,6 +22,10 @@ public class StatementPhi implements StatementLValue { this.previousVersions = new ArrayList<>(); } + public PreviousSymbol getPreviousVersion(int i) { + return previousVersions.get(i); + } + /** * 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. diff --git a/src/dk/camelot64/kickc/icl/StatementReturn.java b/src/dk/camelot64/kickc/icl/StatementReturn.java index 46402b539..3cb17c42d 100644 --- a/src/dk/camelot64/kickc/icl/StatementReturn.java +++ b/src/dk/camelot64/kickc/icl/StatementReturn.java @@ -25,7 +25,4 @@ public class StatementReturn implements Statement { return "return "+(value==null?"":value); } - public void setValue(RValue value) { - this.value = value; - } } diff --git a/src/dk/camelot64/kickc/icl/Symbol.java b/src/dk/camelot64/kickc/icl/Symbol.java index 484a339a0..f9a225e56 100644 --- a/src/dk/camelot64/kickc/icl/Symbol.java +++ b/src/dk/camelot64/kickc/icl/Symbol.java @@ -13,5 +13,5 @@ public interface Symbol extends Value { Scope getScope(); - + int getScopeDepth(); } diff --git a/src/dk/camelot64/kickc/icl/Variable.java b/src/dk/camelot64/kickc/icl/Variable.java index f3939efae..ac45e654a 100644 --- a/src/dk/camelot64/kickc/icl/Variable.java +++ b/src/dk/camelot64/kickc/icl/Variable.java @@ -93,4 +93,14 @@ public abstract class Variable implements Symbol, RValue, LValue { public Scope getScope() { return scope; } + + @Override + public int getScopeDepth() { + if(scope==null) { + return 0; + } else { + return scope.getScopeDepth()+1; + } + } + } diff --git a/src/dk/camelot64/kickc/icl/VariableUnversioned.java b/src/dk/camelot64/kickc/icl/VariableUnversioned.java index c6bc7c5f5..42b73ade5 100644 --- a/src/dk/camelot64/kickc/icl/VariableUnversioned.java +++ b/src/dk/camelot64/kickc/icl/VariableUnversioned.java @@ -31,4 +31,10 @@ public class VariableUnversioned extends Variable { public boolean isIntermediate() { return false; } + + public VariableVersion createVersion() { + VariableVersion version = new VariableVersion(this, this.getNextVersionNumber()); + getScope().add(version); + return version; + } } diff --git a/src/dk/camelot64/kickc/test/Main.java b/src/dk/camelot64/kickc/test/Main.java index 5e3495d49..2f1131405 100644 --- a/src/dk/camelot64/kickc/test/Main.java +++ b/src/dk/camelot64/kickc/test/Main.java @@ -111,7 +111,7 @@ public class Main { } System.out.println("SYMBOLS"); - System.out.println(programScope.toString()); + System.out.println(programScope.getSymbolTableContents()); System.out.println("CONTROL FLOW GRAPH"); System.out.println(controlFlowGraph.toString()); System.out.println("ASSEMBLER");