1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 17:54:40 +00:00

New alias elimination implementation. Optimized register allocation for test.

This commit is contained in:
jespergravgaard 2017-06-13 22:48:03 +02:00
parent a5204acf79
commit 790feb1dcc
16 changed files with 272 additions and 99 deletions

View File

@ -0,0 +1,2 @@
clc
adc #1

View File

@ -0,0 +1 @@
lda {zpby1}

View File

@ -0,0 +1,3 @@
clc
adc #1
sta {zpby1}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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<Alias> 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<Statement> 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<AliasSet> aliases;
public Aliases() {
this.aliases = new ArrayList<>();
}
public List<Alias> getAliases() {
return aliases;
}
public List<Variable> getAssignmentsToRemove() {
ArrayList<Variable> eliminates = new ArrayList<>();
for (Alias alias : aliases) {
if(alias.isKeepHasDefinition()) {
eliminates.add(alias.getEliminate());
} else {
eliminates.add(alias.getKeep());
}
}
return eliminates;
}
public List<Variable> getSymbolsToRemove() {
ArrayList<Variable> eliminates = new ArrayList<>();
for (Alias alias : aliases) {
eliminates.add(alias.getEliminate());
for (AliasSet alias : aliases) {
eliminates.addAll(alias.getEliminateVars());
}
return eliminates;
}
public Map<Variable, Variable> getReplacements() {
HashMap<Variable, Variable> 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<AliasSet> getAliasSets() {
return aliases;
}
}
public static class AliasSet {
private List<Variable> 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<Variable> 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<Variable> getEliminateVars() {
List<Variable> 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<Alias> 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<Void> candidateEliminator = new ControlFlowGraphBaseVisitor<Void>() {
@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<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@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);

View File

@ -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<RValue> 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

View File

@ -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);
}
}

View File

@ -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<Variable> getAllVariables() {
Collection<Variable> 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) {

View File

@ -47,6 +47,10 @@ public class StatementCall implements StatementLValue {
return parameters;
}
public void setParameters(List<RValue> parameters) {
this.parameters = parameters;
}
public int getNumParameters() {
return parameters.size();
}

View File

@ -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.

View File

@ -25,7 +25,4 @@ public class StatementReturn implements Statement {
return "return "+(value==null?"":value);
}
public void setValue(RValue value) {
this.value = value;
}
}

View File

@ -13,5 +13,5 @@ public interface Symbol extends Value {
Scope getScope();
int getScopeDepth();
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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");