1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-10-10 20:23:47 +00:00

Added constant addition optimization and improved alias-optimization

This commit is contained in:
jespergravgaard 2017-06-03 22:37:12 +02:00
parent 0f3da0ea3e
commit 65f41f874f
14 changed files with 271 additions and 32 deletions

View File

@ -0,0 +1,3 @@
txa
clc
adc #{coby1}

View File

@ -0,0 +1,2 @@
txa
asl

View File

@ -36,4 +36,27 @@ public class ControlFlowGraph {
public Collection<ControlFlowBlock> getAllBlocks() {
return blocks.values();
}
/** Get the assignment of the passed variable.
*
* @param variable The variable to find the assignment for
* @return The assignment. null if the variable is not assigned. The variable is assigned by a Phi-statement instead.
*/
public StatementAssignment getAssignment(Variable variable) {
if(variable instanceof VariableUnversioned) {
throw new RuntimeException("Error attempting to get assignment of unversioned variable, which is not guaranteed to be unique "+variable);
}
for (ControlFlowBlock block : getAllBlocks()) {
for (Statement statement : block.getStatements()) {
if(statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
if(assignment.getLValue().equals(variable)) {
return assignment;
}
}
}
}
return null;
}
}

View File

@ -166,7 +166,7 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
public LValue visitLvalueArray(KickCParser.LvalueArrayContext ctx) {
LValue lval = (LValue) visit(ctx.lvalue());
RValue index = (RValue) visit(ctx.expr());
return new PointerDereferenceIndexed((Variable) lval, (Variable)index);
return new PointerDereferenceIndexed(lval, index);
}
@Override

View File

@ -1,8 +1,6 @@
package dk.camelot64.kickc.icl;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.*;
/** Compiler Pass eliminating alias assignments */
public class Pass2AliasElimination extends Pass2SsaOptimization {
@ -11,55 +9,136 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
super(graph, symbolTable);
}
/**
* Eliminate alias assignments replacing them with the aliassed variable.
*/
@Override
public boolean optimize() {
final Map<Variable, Variable> aliases = findAliases();
removeAssignments(aliases.values());
replaceVariables(aliases);
deleteSymbols(aliases.keySet());
for (Variable var : aliases.keySet()) {
Variable alias = aliases.get(var);
System.out.println("Alias " + var + " " + alias);
final Aliases aliases = findAliases();
removeAssignments(aliases.getAssignmentsToRemove());
replaceVariables(aliases.getReplacements());
deleteSymbols(aliases.getSymbolsToRemove());
for (Alias alias : aliases.getAliases()) {
System.out.println("Alias " + alias.getKeep() + " " + alias.getEliminate());
}
return (aliases.size()>0);
}
private Map<Variable, Variable> findAliases() {
Map<Variable, Variable> candidates = findAliasesCandidates();
private static class Aliases {
private List<Alias> 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());
}
return eliminates;
}
public Map<Variable, Variable> getReplacements() {
HashMap<Variable, Variable> replacements = new HashMap<>();
for (Alias alias : aliases) {
replacements.put(alias.getEliminate(), alias.getKeep());
}
return replacements;
}
public int size() {
return aliases.size();
}
public void add(Variable lValue, Variable rValue) {
if(lValue instanceof VariableVersion && rValue instanceof VariableIntermediate) {
aliases.add(new Alias(lValue, rValue, false));
} else {
aliases.add(new Alias(rValue, lValue, true));
}
}
}
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();
cleanupCandidates(candidates);
return candidates;
}
// Remove all candidates that are used after assignment in phi blocks
private void cleanupCandidates(Map<Variable, Variable> candidates) {
Iterator<Variable> aliasIt = candidates.keySet().iterator();
while (aliasIt.hasNext()) {
final Variable alias = aliasIt.next();
final Variable variable = candidates.get(alias);
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};
final Boolean[] lMatch = {false};
ControlFlowGraphBaseVisitor<Void> candidateEliminator = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitPhi(StatementPhi phi) {
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
if(previousSymbol.getRValue().equals(variable)) {
if (previousSymbol.getRValue().equals(varKeep)) {
rMatch[0] = true;
break;
}
}
if(phi.getLValue().equals(alias)) {
if (phi.getLValue().equals(varEliminate)) {
lMatch[0] = true;
}
return null;
}
};
candidateEliminator.visitGraph(getGraph());
if(rMatch[0] && lMatch[0]) {
System.out.println("Alias candidate removed " + alias + " " + variable);
aliasIt.remove();
if (rMatch[0] && lMatch[0]) {
System.out.println("Alias candidate removed " + varEliminate + " " + varKeep);
candidateIt.remove();
}
}
}
@ -68,8 +147,8 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
* Find variables that have constant values.
* @return Map from Variable to the Constant value
*/
private Map<Variable, Variable> findAliasesCandidates() {
final Map<Variable, Variable> aliases = new HashMap<>();
private Aliases findAliasesCandidates() {
final Aliases aliases = new Aliases();
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitAssignment(StatementAssignment assignment) {
@ -78,7 +157,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
if (assignment.getRValue1() == null && assignment.getOperator() == null && assignment.getRValue2() instanceof Variable) {
// Alias assignment
Variable alias = (Variable) assignment.getRValue2();
aliases.put(alias, variable);
aliases.add(variable, alias);
}
}
return null;
@ -91,7 +170,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
if(previousSymbol.getRValue() instanceof Variable) {
VariableVersion variable = phi.getLValue();
Variable alias = (Variable) previousSymbol.getRValue();
aliases.put(alias, variable);
aliases.add(variable, alias);
}
}
return null;

View File

@ -0,0 +1,93 @@
package dk.camelot64.kickc.icl;
/** Compiler Pass eliminating several additions of constants by consolidating them to a single (compile time) constant c1+v+c2 => (c1+c2)+v */
public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
public Pass2ConstantAdditionElimination(ControlFlowGraph graph, SymbolTable symbolTable) {
super(graph, symbolTable);
}
/**
* For assignments with a constant part the variable part is examined looking for constants to consolidate into the constant.
* @return true optimization was performed. false if no optimization was possible.
*/
@Override
public boolean optimize() {
boolean optimized = false;
// Examine all assigments - performing constant consolidation
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
for (Statement statement : block.getStatements()) {
if(statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
if(assignment.getOperator()!=null && "+".equals(assignment.getOperator().getOperator())) {
if(assignment.getRValue1() instanceof ConstantInteger && assignment.getRValue2() instanceof Variable) {
Variable variable = (Variable) assignment.getRValue2();
ConstantInteger consolidated = consolidateSubConstants(variable);
if(consolidated!=null) {
ConstantInteger const1 = (ConstantInteger) assignment.getRValue1();
assignment.setRValue1(new ConstantInteger(const1.getNumber()+consolidated.getNumber()));
optimized = true;
System.out.println("Consolidated constant in assignment "+assignment.getLValue());
}
} else if(assignment.getRValue1() instanceof Variable && assignment.getRValue2() instanceof ConstantInteger) {
Variable variable = (Variable) assignment.getRValue1();
ConstantInteger consolidated = consolidateSubConstants(variable);
if(consolidated!=null) {
ConstantInteger const2 = (ConstantInteger) assignment.getRValue2();
assignment.setRValue2(new ConstantInteger(const2.getNumber()+consolidated.getNumber()));
optimized = true;
System.out.println("Consolidated constant in assignment "+assignment.getLValue());
}
}
}
}
}
}
return optimized;
}
/**
* Gather up constants from sub addition expressions of a variable, remove them there, and return the aggregated sum.
* @param variable The variable to examine
* @return The consolidated constant. Null if no sub-constants were found.
*/
private ConstantInteger consolidateSubConstants(Variable variable) {
StatementAssignment assignment = getGraph().getAssignment(variable);
if(assignment!=null && assignment.getOperator()!=null && "+".equals(assignment.getOperator().getOperator())) {
if(assignment.getRValue1() instanceof ConstantInteger) {
ConstantInteger constant = (ConstantInteger) assignment.getRValue1();
assignment.setRValue1(null);
assignment.setOperator(null);
return constant;
} else if(assignment.getRValue2() instanceof ConstantInteger) {
ConstantInteger constant = (ConstantInteger) assignment.getRValue2();
assignment.setRValue2(assignment.getRValue1());
assignment.setOperator(null);
assignment.setRValue1(null);
return constant;
} else {
ConstantInteger const1 = null;
if(assignment.getRValue1() instanceof Variable) {
const1 = consolidateSubConstants((Variable) assignment.getRValue1());
}
ConstantInteger const2 = null;
if(assignment.getRValue2() instanceof Variable) {
const2 = consolidateSubConstants((Variable) assignment.getRValue2());
}
ConstantInteger result = null;
if(const1!=null) {
result = const1;
if(const2!=null) {
result = new ConstantInteger(const1.getNumber()+const2.getNumber());
}
} else if(const2!=null) {
result = const2;
}
return result;
}
}
return null;
}
}

View File

@ -12,8 +12,7 @@ public class Pass2ConstantPropagation extends Pass2SsaOptimization {
/**
* Propagate constants, replacing variables with constants where possible.
* @return true if no more constant propagation is possible. (no constant propagation was performed)
* false if more constant propagation might be possible. (signalling another call)
* @return true optimization was performed. false if no optimization was possible.
*/
@Override
public boolean optimize() {

View File

@ -63,8 +63,10 @@ public class Pass3RegisterAllocation {
allocation.allocate(symbols.getVariable("v#3"), new RegisterAllocation.RegisterAByte());
allocation.allocate(symbols.getVariable("v#4"), new RegisterAllocation.RegisterAByte());
allocation.allocate(symbols.getVariable("v#5"), new RegisterAllocation.RegisterAByte());
allocation.allocate(symbols.getVariable("$0"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("$0"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("$1"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("$2"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("$3"), new RegisterAllocation.RegisterAByte());
symbols.setAllocation(allocation);
}

View File

@ -76,4 +76,7 @@ public class StatementAssignment implements Statement {
rValue2 ;
}
public void setOperator(Operator operator) {
this.operator = operator;
}
}

View File

@ -58,6 +58,9 @@ public class StatementPhi implements Statement {
}
public void setLValue(Variable lValue) {
if(!(lValue instanceof VariableVersion)) {
throw new RuntimeException("Error modifying phi-statement lValue "+this.lValue+". Attempt to set to non-versioned variable "+lValue);
}
this.lValue = (VariableVersion) lValue;
}

View File

@ -23,4 +23,22 @@ public class VariableVersion extends Variable {
public VariableUnversioned getVersionOf() {
return versionOf;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
VariableVersion that = (VariableVersion) o;
return versionOf != null ? versionOf.equals(that.versionOf) : that.versionOf == null;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (versionOf != null ? versionOf.hashCode() : 0);
return result;
}
}

View File

@ -13,7 +13,7 @@ import java.util.List;
/** Test my KickC Grammar */
public class Main {
public static void main(String[] args) throws IOException {
final String fileName = "src/dk/camelot64/kickc/test/bresenhamarr.kc";
final String fileName = "src/dk/camelot64/kickc/test/fibmem.kc";
final CharStream input = CharStreams.fromFileName(fileName);
System.out.println(input.toString());
KickCLexer lexer = new KickCLexer(input);
@ -45,6 +45,7 @@ public class Main {
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, symbolTable));
optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, symbolTable));
optimizations.add(new Pass2ConstantAdditionElimination(controlFlowGraph, symbolTable));
optimizations.add(new Pass2AliasElimination(controlFlowGraph, symbolTable));
optimizations.add(new Pass2RedundantPhiElimination(controlFlowGraph, symbolTable));
optimizations.add(new Pass2SelfPhiElimination(controlFlowGraph, symbolTable));

View File

@ -0,0 +1,6 @@
byte b = 5;
while(b<10) {
byte c=b;
byte d=c+2;
b = b+1;
}

View File

@ -0,0 +1,7 @@
byte[16] p = $1100;
byte i = 5;
do {
byte c=2;
p[i] = 15+i+c+i+2;
i = i+1;
} while(i<10)