mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-04-06 15:41:05 +00:00
Added constant addition optimization and improved alias-optimization
This commit is contained in:
parent
0f3da0ea3e
commit
65f41f874f
@ -0,0 +1,3 @@
|
||||
txa
|
||||
clc
|
||||
adc #{coby1}
|
2
src/dk/camelot64/kickc/asm/fragment/aby=xby_plus_xby.asm
Normal file
2
src/dk/camelot64/kickc/asm/fragment/aby=xby_plus_xby.asm
Normal file
@ -0,0 +1,2 @@
|
||||
txa
|
||||
asl
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -76,4 +76,7 @@ public class StatementAssignment implements Statement {
|
||||
rValue2 ;
|
||||
}
|
||||
|
||||
public void setOperator(Operator operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
6
src/dk/camelot64/kickc/test/alias.kc
Normal file
6
src/dk/camelot64/kickc/test/alias.kc
Normal file
@ -0,0 +1,6 @@
|
||||
byte b = 5;
|
||||
while(b<10) {
|
||||
byte c=b;
|
||||
byte d=c+2;
|
||||
b = b+1;
|
||||
}
|
7
src/dk/camelot64/kickc/test/minus.kc
Normal file
7
src/dk/camelot64/kickc/test/minus.kc
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user