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:
parent
a5204acf79
commit
790feb1dcc
2
src/dk/camelot64/kickc/asm/fragment/aby=aby_plus_1.asm
Normal file
2
src/dk/camelot64/kickc/asm/fragment/aby=aby_plus_1.asm
Normal file
@ -0,0 +1,2 @@
|
||||
clc
|
||||
adc #1
|
1
src/dk/camelot64/kickc/asm/fragment/aby=zpby1.asm
Normal file
1
src/dk/camelot64/kickc/asm/fragment/aby=zpby1.asm
Normal file
@ -0,0 +1 @@
|
||||
lda {zpby1}
|
3
src/dk/camelot64/kickc/asm/fragment/zpby1=aby_plus_1.asm
Normal file
3
src/dk/camelot64/kickc/asm/fragment/zpby1=aby_plus_1.asm
Normal file
@ -0,0 +1,3 @@
|
||||
clc
|
||||
adc #1
|
||||
sta {zpby1}
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -25,7 +25,4 @@ public class StatementReturn implements Statement {
|
||||
return "return "+(value==null?"":value);
|
||||
}
|
||||
|
||||
public void setValue(RValue value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
@ -13,5 +13,5 @@ public interface Symbol extends Value {
|
||||
|
||||
Scope getScope();
|
||||
|
||||
|
||||
int getScopeDepth();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user