mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-08-09 04:25:12 +00:00
Now supporting fibonacci array generation
This commit is contained in:
@@ -101,6 +101,8 @@ public class AsmFragment {
|
|||||||
private static String getOperatorFragmentName(Operator operator) {
|
private static String getOperatorFragmentName(Operator operator) {
|
||||||
String op = operator.getOperator();
|
String op = operator.getOperator();
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
case "*":
|
||||||
|
return "_star_";
|
||||||
case "+":
|
case "+":
|
||||||
return "_plus_";
|
return "_plus_";
|
||||||
case "-":
|
case "-":
|
||||||
@@ -198,8 +200,8 @@ public class AsmFragment {
|
|||||||
bindings.put(name, value);
|
bindings.put(name, value);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
} else if (value instanceof PointerDereference) {
|
} else if (value instanceof PointerDereferenceVariable) {
|
||||||
PointerDereference deref = (PointerDereference) value;
|
PointerDereferenceVariable deref = (PointerDereferenceVariable) value;
|
||||||
Variable pointer = deref.getPointer();
|
Variable pointer = deref.getPointer();
|
||||||
RegisterAllocation.Register register = symbols.getRegister(pointer);
|
RegisterAllocation.Register register = symbols.getRegister(pointer);
|
||||||
if (RegisterAllocation.RegisterType.ZP_PTR_BYTE.equals(register.getType())) {
|
if (RegisterAllocation.RegisterType.ZP_PTR_BYTE.equals(register.getType())) {
|
||||||
@@ -207,13 +209,21 @@ public class AsmFragment {
|
|||||||
bindings.put(name, value);
|
bindings.put(name, value);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
} else if (value instanceof PointerDereferenceConstant) {
|
||||||
|
PointerDereferenceConstant deref = (PointerDereferenceConstant) value;
|
||||||
|
Constant pointer = deref.getPointer();
|
||||||
|
if(pointer instanceof ConstantInteger) {
|
||||||
|
String name = "coptr"+ nextConstByteIdx++;
|
||||||
|
bindings.put(name, value);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
} else if (value instanceof ConstantInteger) {
|
} else if (value instanceof ConstantInteger) {
|
||||||
ConstantInteger intValue = (ConstantInteger) value;
|
ConstantInteger intValue = (ConstantInteger) value;
|
||||||
if (intValue.getType().equals(SymbolTypeBasic.BYTE)) {
|
if (SymbolTypeBasic.BYTE.equals(intValue.getType())) {
|
||||||
String name = "coby" + nextConstByteIdx++;
|
String name = "coby" + nextConstByteIdx++;
|
||||||
bindings.put(name, value);
|
bindings.put(name, value);
|
||||||
return name;
|
return name;
|
||||||
} else if (intValue.getType().equals(SymbolTypeBasic.WORD)) {
|
} else if (SymbolTypeBasic.WORD.equals(intValue.getType())) {
|
||||||
String name = "cowo" + nextConstByteIdx++;
|
String name = "cowo" + nextConstByteIdx++;
|
||||||
bindings.put(name, value);
|
bindings.put(name, value);
|
||||||
return name;
|
return name;
|
||||||
@@ -234,6 +244,9 @@ public class AsmFragment {
|
|||||||
*/
|
*/
|
||||||
public String getBoundValue(String name) {
|
public String getBoundValue(String name) {
|
||||||
Value boundValue = getBinding(name);
|
Value boundValue = getBinding(name);
|
||||||
|
if(boundValue==null) {
|
||||||
|
throw new RuntimeException("Binding not found in fragment '" + name+"'");
|
||||||
|
}
|
||||||
String bound;
|
String bound;
|
||||||
if (boundValue instanceof Variable) {
|
if (boundValue instanceof Variable) {
|
||||||
RegisterAllocation.Register register = symbols.getRegister((Variable) boundValue);
|
RegisterAllocation.Register register = symbols.getRegister((Variable) boundValue);
|
||||||
@@ -246,8 +259,8 @@ public class AsmFragment {
|
|||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Register Type not implemented " + register);
|
throw new RuntimeException("Register Type not implemented " + register);
|
||||||
}
|
}
|
||||||
} else if(boundValue instanceof PointerDereference) {
|
} else if(boundValue instanceof PointerDereferenceVariable) {
|
||||||
PointerDereference deref = (PointerDereference) boundValue;
|
PointerDereferenceVariable deref = (PointerDereferenceVariable) boundValue;
|
||||||
Variable pointer = deref.getPointer();
|
Variable pointer = deref.getPointer();
|
||||||
RegisterAllocation.Register register = symbols.getRegister(pointer);
|
RegisterAllocation.Register register = symbols.getRegister(pointer);
|
||||||
if(register instanceof RegisterAllocation.RegisterZpPointerByte) {
|
if(register instanceof RegisterAllocation.RegisterZpPointerByte) {
|
||||||
@@ -255,6 +268,15 @@ public class AsmFragment {
|
|||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
|
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
|
||||||
}
|
}
|
||||||
|
} else if(boundValue instanceof PointerDereferenceConstant) {
|
||||||
|
PointerDereferenceConstant deref = (PointerDereferenceConstant) boundValue;
|
||||||
|
Constant pointer = deref.getPointer();
|
||||||
|
if (pointer instanceof ConstantInteger) {
|
||||||
|
ConstantInteger intPointer = (ConstantInteger) pointer;
|
||||||
|
bound = Integer.toString(intPointer.getNumber());
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
|
||||||
|
}
|
||||||
} else if (boundValue instanceof ConstantInteger) {
|
} else if (boundValue instanceof ConstantInteger) {
|
||||||
ConstantInteger boundInt = (ConstantInteger) boundValue;
|
ConstantInteger boundInt = (ConstantInteger) boundValue;
|
||||||
if (boundInt.getType().equals(SymbolTypeBasic.BYTE)) {
|
if (boundInt.getType().equals(SymbolTypeBasic.BYTE)) {
|
||||||
|
2
src/dk/camelot64/kickc/asm/fragment/coptr1=coby2.asm
Normal file
2
src/dk/camelot64/kickc/asm/fragment/coptr1=coby2.asm
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
lda #{coby2}
|
||||||
|
sta {coptr1}
|
@@ -0,0 +1,2 @@
|
|||||||
|
cpx #{coby1}
|
||||||
|
bcc {la1}
|
@@ -0,0 +1,2 @@
|
|||||||
|
lda {cowo1}
|
||||||
|
sta {zpby1}
|
@@ -0,0 +1,3 @@
|
|||||||
|
ldy #0
|
||||||
|
lda ({zpptrby1}),y
|
||||||
|
sta {zpby1}
|
@@ -0,0 +1,3 @@
|
|||||||
|
dex
|
||||||
|
stx {zpby1}
|
||||||
|
inx
|
@@ -0,0 +1,4 @@
|
|||||||
|
txa
|
||||||
|
sec
|
||||||
|
sbc #{coby1}
|
||||||
|
sta {zpby1}
|
3
src/dk/camelot64/kickc/asm/fragment/zpiby1=zpby1.asm
Normal file
3
src/dk/camelot64/kickc/asm/fragment/zpiby1=zpby1.asm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ldy #0
|
||||||
|
lda {zpby1}
|
||||||
|
sta ({zpiby1}),y
|
@@ -0,0 +1,7 @@
|
|||||||
|
txa
|
||||||
|
clc
|
||||||
|
adc #<{cowo1}
|
||||||
|
sta {zpptrby1}
|
||||||
|
lda #0
|
||||||
|
adc #>{cowo1}
|
||||||
|
sta {zpptrby1}+1
|
@@ -0,0 +1,7 @@
|
|||||||
|
lda #<{cowo1}
|
||||||
|
clc
|
||||||
|
adc {zpby1}
|
||||||
|
sta {zpptrby1}
|
||||||
|
lda #>{cowo1}
|
||||||
|
adc #0
|
||||||
|
sta {zpptrby1}+1
|
@@ -165,7 +165,7 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
VariableIntermediate tmpVar = symbolTable.newIntermediateAssignment();
|
VariableIntermediate tmpVar = symbolTable.newIntermediateAssignment();
|
||||||
Statement stmt = new StatementAssignment(tmpVar, lval, operator, index);
|
Statement stmt = new StatementAssignment(tmpVar, lval, operator, index);
|
||||||
sequence.addStatement(stmt);
|
sequence.addStatement(stmt);
|
||||||
return new PointerDereference(tmpVar);
|
return new PointerDereferenceVariable(tmpVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -218,7 +218,10 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
VariableIntermediate tmpVar = symbolTable.newIntermediateAssignment();
|
VariableIntermediate tmpVar = symbolTable.newIntermediateAssignment();
|
||||||
Statement stmt = new StatementAssignment(tmpVar, array, operator, index);
|
Statement stmt = new StatementAssignment(tmpVar, array, operator, index);
|
||||||
sequence.addStatement(stmt);
|
sequence.addStatement(stmt);
|
||||||
return new PointerDereference(tmpVar);
|
VariableIntermediate tmpVar2 = symbolTable.newIntermediateAssignment();
|
||||||
|
Statement stmt2 = new StatementAssignment(tmpVar2, null, new Operator("*"), tmpVar );
|
||||||
|
sequence.addStatement(stmt2);
|
||||||
|
return tmpVar2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -5,7 +5,7 @@ import java.util.Iterator;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/** Compiler Pass eliminating alias assignments */
|
/** Compiler Pass eliminating alias assignments */
|
||||||
public class Pass2AliasElimination extends Pass2Optimization {
|
public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||||
|
|
||||||
public Pass2AliasElimination(ControlFlowGraph graph, SymbolTable symbolTable) {
|
public Pass2AliasElimination(ControlFlowGraph graph, SymbolTable symbolTable) {
|
||||||
super(graph, symbolTable);
|
super(graph, symbolTable);
|
||||||
|
@@ -1,14 +1,13 @@
|
|||||||
package dk.camelot64.kickc.icl;
|
package dk.camelot64.kickc.icl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiler Pass simplifying conditional jumps that are simple comparisons
|
* Compiler Pass simplifying conditional jumps that are simple comparisons
|
||||||
*/
|
*/
|
||||||
public class Pass2ConditionalJumpSimplification extends Pass2Optimization {
|
public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
|
||||||
|
|
||||||
private Map<Variable, List<Statement>> allUsages;
|
private Map<Variable, List<Statement>> allUsages;
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/** Compiler Pass propagating constants in expressions eliminating constant variables */
|
/** Compiler Pass propagating constants in expressions eliminating constant variables */
|
||||||
public class Pass2ConstantPropagation extends Pass2Optimization {
|
public class Pass2ConstantPropagation extends Pass2SsaOptimization {
|
||||||
|
|
||||||
public Pass2ConstantPropagation(ControlFlowGraph graph, SymbolTable symbolTable) {
|
public Pass2ConstantPropagation(ControlFlowGraph graph, SymbolTable symbolTable) {
|
||||||
super(graph, symbolTable);
|
super(graph, symbolTable);
|
||||||
@@ -47,7 +47,9 @@ public class Pass2ConstantPropagation extends Pass2Optimization {
|
|||||||
} else {
|
} else {
|
||||||
// Constant unary expression
|
// Constant unary expression
|
||||||
Constant constant = calculateUnary(assignment.getOperator(), (Constant) assignment.getRValue2());
|
Constant constant = calculateUnary(assignment.getOperator(), (Constant) assignment.getRValue2());
|
||||||
constants.put(variable, constant);
|
if(constant!=null) {
|
||||||
|
constants.put(variable, constant);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (assignment.getRValue1() instanceof Constant && assignment.getRValue2() instanceof Constant) {
|
} else if (assignment.getRValue1() instanceof Constant && assignment.getRValue2() instanceof Constant) {
|
||||||
// Constant binary expression
|
// Constant binary expression
|
||||||
@@ -141,6 +143,9 @@ public class Pass2ConstantPropagation extends Pass2Optimization {
|
|||||||
case "+": {
|
case "+": {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
case "*": { // pointer dereference
|
||||||
|
return null;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("Unhandled Unary Operator " + operator.getOperator());
|
throw new RuntimeException("Unhandled Unary Operator " + operator.getOperator());
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@ package dk.camelot64.kickc.icl;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/** Pass that culls empty control flow blocks from the program */
|
/** Pass that culls empty control flow blocks from the program */
|
||||||
public class Pass2CullEmptyBlocks extends Pass2Optimization {
|
public class Pass2CullEmptyBlocks extends Pass2SsaOptimization {
|
||||||
|
|
||||||
public Pass2CullEmptyBlocks(ControlFlowGraph graph, SymbolTable symbolTable) {
|
public Pass2CullEmptyBlocks(ControlFlowGraph graph, SymbolTable symbolTable) {
|
||||||
super(graph, symbolTable);
|
super(graph, symbolTable);
|
||||||
|
@@ -4,7 +4,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/** Compiler Pass eliminating redundant phi functions */
|
/** Compiler Pass eliminating redundant phi functions */
|
||||||
public class Pass2RedundantPhiElimination extends Pass2Optimization{
|
public class Pass2RedundantPhiElimination extends Pass2SsaOptimization {
|
||||||
|
|
||||||
public Pass2RedundantPhiElimination(ControlFlowGraph graph, SymbolTable symbolTable) {
|
public Pass2RedundantPhiElimination(ControlFlowGraph graph, SymbolTable symbolTable) {
|
||||||
super(graph, symbolTable);
|
super(graph, symbolTable);
|
||||||
|
@@ -1,11 +1,9 @@
|
|||||||
package dk.camelot64.kickc.icl;
|
package dk.camelot64.kickc.icl;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/** Compiler Pass eliminating phi self assignments */
|
/** Compiler Pass eliminating phi self assignments */
|
||||||
public class Pass2SelfPhiElimination extends Pass2Optimization{
|
public class Pass2SelfPhiElimination extends Pass2SsaOptimization {
|
||||||
|
|
||||||
public Pass2SelfPhiElimination(ControlFlowGraph graph, SymbolTable symbolTable) {
|
public Pass2SelfPhiElimination(ControlFlowGraph graph, SymbolTable symbolTable) {
|
||||||
super(graph, symbolTable);
|
super(graph, symbolTable);
|
||||||
|
@@ -3,15 +3,15 @@ package dk.camelot64.kickc.icl;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimization performed during Compiler Pass 2.
|
* Optimization on Single Static Assignment form (Control Flow Graph) performed during Compiler Pass 2.
|
||||||
* Optimizations are performed repeatedly until none of them yield any result
|
* Optimizations are performed repeatedly until none of them yield any result
|
||||||
* */
|
*/
|
||||||
public abstract class Pass2Optimization {
|
public abstract class Pass2SsaOptimization {
|
||||||
|
|
||||||
private ControlFlowGraph graph;
|
private ControlFlowGraph graph;
|
||||||
private SymbolTable symbolTable;
|
private SymbolTable symbolTable;
|
||||||
|
|
||||||
public Pass2Optimization(ControlFlowGraph graph, SymbolTable symbolTable) {
|
public Pass2SsaOptimization(ControlFlowGraph graph, SymbolTable symbolTable) {
|
||||||
this.graph = graph;
|
this.graph = graph;
|
||||||
this.symbolTable = symbolTable;
|
this.symbolTable = symbolTable;
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,9 @@ public abstract class Pass2Optimization {
|
|||||||
*/
|
*/
|
||||||
public abstract boolean optimize();
|
public abstract boolean optimize();
|
||||||
|
|
||||||
/** Singleton signalling that an RValue is never assigned and can safely be discarded as rvalue in phi-functions.*/
|
/**
|
||||||
|
* Singleton signalling that an RValue is never assigned and can safely be discarded as rvalue in phi-functions.
|
||||||
|
*/
|
||||||
public static RValue VOID = new RValue() {
|
public static RValue VOID = new RValue() {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@@ -41,33 +43,52 @@ public abstract class Pass2Optimization {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace all usages of variables in statements with aliases.
|
* Replace all usages of variables in statements with aliases.
|
||||||
|
*
|
||||||
* @param aliases Variables that have alias values.
|
* @param aliases Variables that have alias values.
|
||||||
*/
|
*/
|
||||||
public void replaceVariables(final Map<Variable, ? extends RValue> aliases) {
|
public void replaceVariables(final Map<Variable, ? extends RValue> aliases) {
|
||||||
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void visitAssignment(StatementAssignment assignment) {
|
public Void visitAssignment(StatementAssignment assignment) {
|
||||||
if(getAlias(aliases, assignment.getLValue()) !=null) {
|
LValue lValue = assignment.getLValue();
|
||||||
RValue alias = getAlias(aliases, assignment.getLValue());
|
if (getAlias(aliases, lValue) != null) {
|
||||||
if(alias instanceof LValue) {
|
RValue alias = getAlias(aliases, lValue);
|
||||||
|
if (alias instanceof LValue) {
|
||||||
assignment.setLValue((LValue) alias);
|
assignment.setLValue((LValue) alias);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Error replacing LValue variable " + lValue + " with " + alias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(getAlias(aliases, assignment.getRValue1())!=null) {
|
if (getAlias(aliases, assignment.getRValue1()) != null) {
|
||||||
assignment.setRValue1(getAlias(aliases, assignment.getRValue1()));
|
assignment.setRValue1(getAlias(aliases, assignment.getRValue1()));
|
||||||
}
|
}
|
||||||
if(getAlias(aliases, assignment.getRValue2())!=null) {
|
if (getAlias(aliases, assignment.getRValue2()) != null) {
|
||||||
assignment.setRValue2(getAlias(aliases, assignment.getRValue2()));
|
assignment.setRValue2(getAlias(aliases, assignment.getRValue2()));
|
||||||
}
|
}
|
||||||
|
// Handle pointer dereference in LValue
|
||||||
|
if (lValue instanceof PointerDereferenceVariable) {
|
||||||
|
PointerDereferenceVariable deref = (PointerDereferenceVariable) lValue;
|
||||||
|
Variable pointer = deref.getPointer();
|
||||||
|
if (getAlias(aliases, pointer) != null) {
|
||||||
|
RValue alias = getAlias(aliases, pointer);
|
||||||
|
if (alias instanceof Variable) {
|
||||||
|
deref.setPointerVariable((Variable) alias);
|
||||||
|
} else if (alias instanceof Constant) {
|
||||||
|
assignment.setLValue(new PointerDereferenceConstant((Constant) alias));
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Error replacing LValue variable " + lValue + " with " + alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
|
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
|
||||||
if(getAlias(aliases, conditionalJump.getRValue1())!=null) {
|
if (getAlias(aliases, conditionalJump.getRValue1()) != null) {
|
||||||
conditionalJump.setRValue1(getAlias(aliases, conditionalJump.getRValue1()));
|
conditionalJump.setRValue1(getAlias(aliases, conditionalJump.getRValue1()));
|
||||||
}
|
}
|
||||||
if(getAlias(aliases, conditionalJump.getRValue2())!=null) {
|
if (getAlias(aliases, conditionalJump.getRValue2()) != null) {
|
||||||
conditionalJump.setRValue2(getAlias(aliases, conditionalJump.getRValue2()));
|
conditionalJump.setRValue2(getAlias(aliases, conditionalJump.getRValue2()));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -75,9 +96,9 @@ public abstract class Pass2Optimization {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitPhi(StatementPhi phi) {
|
public Void visitPhi(StatementPhi phi) {
|
||||||
if(getAlias(aliases, phi.getLValue())!=null) {
|
if (getAlias(aliases, phi.getLValue()) != null) {
|
||||||
RValue alias = getAlias(aliases, phi.getLValue());
|
RValue alias = getAlias(aliases, phi.getLValue());
|
||||||
if(alias instanceof LValue) {
|
if (alias instanceof LValue) {
|
||||||
phi.setLValue((Variable) alias);
|
phi.setLValue((Variable) alias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,15 +119,16 @@ public abstract class Pass2Optimization {
|
|||||||
visitor.visitGraph(graph);
|
visitor.visitGraph(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the alias to use for an RValue.
|
/**
|
||||||
|
* Get the alias to use for an RValue.
|
||||||
*
|
*
|
||||||
* @param aliases The alias map
|
* @param aliases The alias map
|
||||||
* @param rValue The RValue to find an alias for
|
* @param rValue The RValue to find an alias for
|
||||||
* @return The alias to use. Null if no alias exists.
|
* @return The alias to use. Null if no alias exists.
|
||||||
*/
|
*/
|
||||||
private static RValue getAlias(Map<Variable, ? extends RValue> aliases,RValue rValue) {
|
private static RValue getAlias(Map<Variable, ? extends RValue> aliases, RValue rValue) {
|
||||||
RValue alias = aliases.get(rValue);
|
RValue alias = aliases.get(rValue);
|
||||||
while (aliases.get(alias)!=null) {
|
while (aliases.get(alias) != null) {
|
||||||
alias = aliases.get(alias);
|
alias = aliases.get(alias);
|
||||||
}
|
}
|
||||||
return alias;
|
return alias;
|
||||||
@@ -114,14 +136,15 @@ public abstract class Pass2Optimization {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace all usages of a label in statements with another label.
|
* Replace all usages of a label in statements with another label.
|
||||||
|
*
|
||||||
* @param replacements Variables that have alias values.
|
* @param replacements Variables that have alias values.
|
||||||
*/
|
*/
|
||||||
public void replaceLabels(final Map<Label, Label> replacements) {
|
public void replaceLabels(final Map<Label, Label> replacements) {
|
||||||
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
|
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
|
||||||
if(getReplacement(replacements, conditionalJump.getDestination())!=null) {
|
if (getReplacement(replacements, conditionalJump.getDestination()) != null) {
|
||||||
conditionalJump.setDestination(getReplacement(replacements, conditionalJump.getDestination()));
|
conditionalJump.setDestination(getReplacement(replacements, conditionalJump.getDestination()));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -129,7 +152,7 @@ public abstract class Pass2Optimization {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitJump(StatementJump jump) {
|
public Void visitJump(StatementJump jump) {
|
||||||
if(getReplacement(replacements, jump.getDestination())!=null) {
|
if (getReplacement(replacements, jump.getDestination()) != null) {
|
||||||
jump.setDestination(getReplacement(replacements, jump.getDestination()));
|
jump.setDestination(getReplacement(replacements, jump.getDestination()));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -139,7 +162,7 @@ public abstract class Pass2Optimization {
|
|||||||
public Void visitPhi(StatementPhi phi) {
|
public Void visitPhi(StatementPhi phi) {
|
||||||
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
|
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
|
||||||
Label replacement = getReplacement(replacements, previousSymbol.getBlock().getLabel());
|
Label replacement = getReplacement(replacements, previousSymbol.getBlock().getLabel());
|
||||||
if(replacement !=null) {
|
if (replacement != null) {
|
||||||
previousSymbol.setBlock(graph.getBlock(replacement));
|
previousSymbol.setBlock(graph.getBlock(replacement));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,15 +172,16 @@ public abstract class Pass2Optimization {
|
|||||||
visitor.visitGraph(graph);
|
visitor.visitGraph(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the label to use as replacement for another label.
|
/**
|
||||||
|
* Get the label to use as replacement for another label.
|
||||||
*
|
*
|
||||||
* @param replacements The label replacement map
|
* @param replacements The label replacement map
|
||||||
* @param label The label to find a replacement for
|
* @param label The label to find a replacement for
|
||||||
* @return The alias to use. Null if no replacement exists.
|
* @return The alias to use. Null if no replacement exists.
|
||||||
*/
|
*/
|
||||||
private static Label getReplacement(Map<Label, Label> replacements,Label label) {
|
private static Label getReplacement(Map<Label, Label> replacements, Label label) {
|
||||||
Label replacement = replacements.get(label);
|
Label replacement = replacements.get(label);
|
||||||
while (replacements.get(replacement)!=null) {
|
while (replacements.get(replacement) != null) {
|
||||||
replacement = replacements.get(replacement);
|
replacement = replacements.get(replacement);
|
||||||
}
|
}
|
||||||
return replacement;
|
return replacement;
|
||||||
@@ -166,6 +190,7 @@ public abstract class Pass2Optimization {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all assignments to specific LValues from the control flow graph (as they are no longer needed).
|
* Remove all assignments to specific LValues from the control flow graph (as they are no longer needed).
|
||||||
|
*
|
||||||
* @param variables The variables to eliminate
|
* @param variables The variables to eliminate
|
||||||
*/
|
*/
|
||||||
public void removeAssignments(Collection<? extends LValue> variables) {
|
public void removeAssignments(Collection<? extends LValue> variables) {
|
||||||
@@ -177,7 +202,7 @@ public abstract class Pass2Optimization {
|
|||||||
if (variables.contains(assignment.getLValue())) {
|
if (variables.contains(assignment.getLValue())) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
} else if(statement instanceof StatementPhi) {
|
} else if (statement instanceof StatementPhi) {
|
||||||
StatementPhi phi = (StatementPhi) statement;
|
StatementPhi phi = (StatementPhi) statement;
|
||||||
if (variables.contains(phi.getLValue())) {
|
if (variables.contains(phi.getLValue())) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
@@ -189,6 +214,7 @@ public abstract class Pass2Optimization {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove variables from the symbol table
|
* Remove variables from the symbol table
|
||||||
|
*
|
||||||
* @param variables The variables to remove
|
* @param variables The variables to remove
|
||||||
*/
|
*/
|
||||||
public void deleteSymbols(Collection<? extends LValue> variables) {
|
public void deleteSymbols(Collection<? extends LValue> variables) {
|
33
src/dk/camelot64/kickc/icl/Pass5AsmOptimization.java
Normal file
33
src/dk/camelot64/kickc/icl/Pass5AsmOptimization.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package dk.camelot64.kickc.icl;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.asm.AsmLine;
|
||||||
|
import dk.camelot64.kickc.asm.AsmProgram;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Optimization performed on Assembler Code (Asm Code).
|
||||||
|
* Optimizations are performed repeatedly until none of them yield any result
|
||||||
|
**/
|
||||||
|
public class Pass5AsmOptimization {
|
||||||
|
|
||||||
|
private AsmProgram program;
|
||||||
|
|
||||||
|
public Pass5AsmOptimization(AsmProgram program) {
|
||||||
|
this.program = program;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsmProgram getProgram() {
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(List<AsmLine> remove) {
|
||||||
|
for (Iterator<AsmLine> iterator = program.getLines().iterator(); iterator.hasNext(); ) {
|
||||||
|
AsmLine line = iterator.next();
|
||||||
|
if (remove.contains(line)) {
|
||||||
|
System.out.println("Removing instruction "+line.getAsm());
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -10,23 +10,20 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** Optimize assembler code by removing jumps to labels immediately following the jump */
|
/** Optimize assembler code by removing jumps to labels immediately following the jump */
|
||||||
public class Pass5NextJumpElimination {
|
public class Pass5NextJumpElimination extends Pass5AsmOptimization {
|
||||||
|
|
||||||
private AsmProgram program;
|
|
||||||
|
|
||||||
public Pass5NextJumpElimination(AsmProgram program) {
|
public Pass5NextJumpElimination(AsmProgram program) {
|
||||||
this.program = program;
|
super(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean optimize() {
|
public boolean optimize() {
|
||||||
List<AsmLine> remove = new ArrayList<>();
|
List<AsmLine> removeLines = new ArrayList<>();
|
||||||
AsmInstruction candidate = null;
|
AsmInstruction candidate = null;
|
||||||
for (AsmLine line : program.getLines()) {
|
for (AsmLine line : getProgram().getLines()) {
|
||||||
if(candidate!=null) {
|
if(candidate!=null) {
|
||||||
if(line instanceof AsmLabel) {
|
if(line instanceof AsmLabel) {
|
||||||
if(((AsmLabel) line).getLabel().equals(candidate.getParameter())) {
|
if(((AsmLabel) line).getLabel().equals(candidate.getParameter())) {
|
||||||
remove.add(candidate);
|
removeLines.add(candidate);
|
||||||
candidate = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,13 +35,7 @@ public class Pass5NextJumpElimination {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Iterator<AsmLine> iterator = program.getLines().iterator(); iterator.hasNext(); ) {
|
remove(removeLines);
|
||||||
AsmLine line = iterator.next();
|
return removeLines.size()>0;
|
||||||
if (remove.contains(line)) {
|
|
||||||
System.out.println("Removing jump to next instruction "+line.getAsm());
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return remove.size()>0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,8 @@ public class PassTypeInference {
|
|||||||
if (operator == null || assignment.getRValue1() == null) {
|
if (operator == null || assignment.getRValue1() == null) {
|
||||||
// Copy operation or Unary operation
|
// Copy operation or Unary operation
|
||||||
RValue rValue = assignment.getRValue2();
|
RValue rValue = assignment.getRValue2();
|
||||||
SymbolType type = inferType(rValue);
|
SymbolType subType = inferType(rValue);
|
||||||
|
SymbolType type = inferType(operator, subType);
|
||||||
symbol.setInferredType(type);
|
symbol.setInferredType(type);
|
||||||
} else {
|
} else {
|
||||||
// Binary operation
|
// Binary operation
|
||||||
@@ -33,6 +34,23 @@ public class PassTypeInference {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SymbolType inferType(Operator operator, SymbolType subType) {
|
||||||
|
if(operator==null) {
|
||||||
|
return subType;
|
||||||
|
}
|
||||||
|
String op = operator.getOperator();
|
||||||
|
switch (op) {
|
||||||
|
case "*":
|
||||||
|
if(subType instanceof SymbolTypePointer) {
|
||||||
|
return ((SymbolTypePointer) subType).getElementType();
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Type error: Dereferencing a non-pointer "+subType);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return subType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private SymbolType inferType(SymbolType type1, Operator operator, SymbolType type2) {
|
private SymbolType inferType(SymbolType type1, Operator operator, SymbolType type2) {
|
||||||
String op = operator.getOperator();
|
String op = operator.getOperator();
|
||||||
switch (op) {
|
switch (op) {
|
||||||
@@ -55,7 +73,15 @@ public class PassTypeInference {
|
|||||||
if (type1 instanceof SymbolTypePointer && (type2.equals(SymbolTypeBasic.BYTE) || type2.equals(SymbolTypeBasic.WORD))) {
|
if (type1 instanceof SymbolTypePointer && (type2.equals(SymbolTypeBasic.BYTE) || type2.equals(SymbolTypeBasic.WORD))) {
|
||||||
return new SymbolTypePointer(((SymbolTypePointer) type1).getElementType());
|
return new SymbolTypePointer(((SymbolTypePointer) type1).getElementType());
|
||||||
}
|
}
|
||||||
|
if (type1 instanceof SymbolTypePointer && type2 instanceof SymbolTypePointer) {
|
||||||
|
SymbolType elmType1 = ((SymbolTypePointer) type1).getElementType();
|
||||||
|
SymbolType elmType2 = ((SymbolTypePointer) type2).getElementType();
|
||||||
|
return inferType(elmType1, operator, elmType2);
|
||||||
|
}
|
||||||
case "*":
|
case "*":
|
||||||
|
if(type1==null && type2 instanceof SymbolTypePointer) {
|
||||||
|
return ((SymbolTypePointer) type2).getElementType();
|
||||||
|
}
|
||||||
case "/":
|
case "/":
|
||||||
if (SymbolTypeBasic.WORD.equals(type1) || SymbolTypeBasic.WORD.equals(type2)) {
|
if (SymbolTypeBasic.WORD.equals(type1) || SymbolTypeBasic.WORD.equals(type2)) {
|
||||||
return SymbolTypeBasic.WORD;
|
return SymbolTypeBasic.WORD;
|
||||||
|
@@ -1,20 +1,8 @@
|
|||||||
package dk.camelot64.kickc.icl;
|
package dk.camelot64.kickc.icl;
|
||||||
|
|
||||||
/** A dereferenced pointer */
|
/** A dereferenced pointer */
|
||||||
public class PointerDereference implements LValue {
|
public interface PointerDereference extends LValue {
|
||||||
|
|
||||||
private Variable pointer;
|
Value getPointer();
|
||||||
|
|
||||||
public PointerDereference(Variable pointer) {
|
|
||||||
this.pointer = pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Variable getPointer() {
|
|
||||||
return pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "*(" + pointer + ')';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
24
src/dk/camelot64/kickc/icl/PointerDereferenceConstant.java
Normal file
24
src/dk/camelot64/kickc/icl/PointerDereferenceConstant.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package dk.camelot64.kickc.icl;
|
||||||
|
|
||||||
|
/** A dereferenced constant pointer */
|
||||||
|
public class PointerDereferenceConstant implements LValue {
|
||||||
|
|
||||||
|
private Constant pointer;
|
||||||
|
|
||||||
|
public PointerDereferenceConstant(Constant pointer) {
|
||||||
|
this.pointer = pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Constant getPointer() {
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Constant getPointerConstant() {
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "*(" + pointer + ')';
|
||||||
|
}
|
||||||
|
}
|
28
src/dk/camelot64/kickc/icl/PointerDereferenceVariable.java
Normal file
28
src/dk/camelot64/kickc/icl/PointerDereferenceVariable.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package dk.camelot64.kickc.icl;
|
||||||
|
|
||||||
|
/** A dereferenced variable pointer */
|
||||||
|
public class PointerDereferenceVariable implements PointerDereference {
|
||||||
|
|
||||||
|
private Variable pointer;
|
||||||
|
|
||||||
|
public PointerDereferenceVariable(Variable pointer) {
|
||||||
|
this.pointer = pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Variable getPointer() {
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Variable getPointerVariable() {
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "*(" + pointer + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointerVariable(Variable pointer) {
|
||||||
|
this.pointer = pointer;
|
||||||
|
}
|
||||||
|
}
|
@@ -13,7 +13,7 @@ import java.util.List;
|
|||||||
/** Test my KickC Grammar */
|
/** Test my KickC Grammar */
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
final String fileName = "src/dk/camelot64/kickc/test/mem.kc";
|
final String fileName = "src/dk/camelot64/kickc/test/fibmem.kc";
|
||||||
final CharStream input = CharStreams.fromFileName(fileName);
|
final CharStream input = CharStreams.fromFileName(fileName);
|
||||||
System.out.println(input.toString());
|
System.out.println(input.toString());
|
||||||
KickCLexer lexer = new KickCLexer(input);
|
KickCLexer lexer = new KickCLexer(input);
|
||||||
@@ -42,7 +42,7 @@ public class Main {
|
|||||||
new Pass1GenerateSingleStaticAssignmentForm(symbolTable, controlFlowGraph);
|
new Pass1GenerateSingleStaticAssignmentForm(symbolTable, controlFlowGraph);
|
||||||
pass1GenerateSingleStaticAssignmentForm.generate();
|
pass1GenerateSingleStaticAssignmentForm.generate();
|
||||||
|
|
||||||
List<Pass2Optimization> optimizations = new ArrayList<>();
|
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
|
||||||
optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, symbolTable));
|
optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, symbolTable));
|
||||||
optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, symbolTable));
|
optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, symbolTable));
|
||||||
optimizations.add(new Pass2AliasElimination(controlFlowGraph, symbolTable));
|
optimizations.add(new Pass2AliasElimination(controlFlowGraph, symbolTable));
|
||||||
@@ -53,14 +53,14 @@ public class Main {
|
|||||||
System.out.println("INITIAL CONTROL FLOW GRAPH");
|
System.out.println("INITIAL CONTROL FLOW GRAPH");
|
||||||
System.out.println(controlFlowGraph.toString());
|
System.out.println(controlFlowGraph.toString());
|
||||||
|
|
||||||
boolean optimized = true;
|
boolean ssaOptimized = true;
|
||||||
while (optimized) {
|
while (ssaOptimized) {
|
||||||
optimized = false;
|
ssaOptimized = false;
|
||||||
for (Pass2Optimization optimization : optimizations) {
|
for (Pass2SsaOptimization optimization : optimizations) {
|
||||||
boolean stepOptimized = optimization.optimize();
|
boolean stepOptimized = optimization.optimize();
|
||||||
if (stepOptimized) {
|
if (stepOptimized) {
|
||||||
System.out.println("Succesful optimization "+optimization);
|
System.out.println("Succesful optimization "+optimization);
|
||||||
optimized = true;
|
ssaOptimized = true;
|
||||||
System.out.println("CONTROL FLOW GRAPH");
|
System.out.println("CONTROL FLOW GRAPH");
|
||||||
System.out.println(controlFlowGraph.toString());
|
System.out.println(controlFlowGraph.toString());
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,10 @@ public class Main {
|
|||||||
Pass4CodeGeneration pass4CodeGeneration = new Pass4CodeGeneration(controlFlowGraph, symbolTable);
|
Pass4CodeGeneration pass4CodeGeneration = new Pass4CodeGeneration(controlFlowGraph, symbolTable);
|
||||||
AsmProgram asmProgram = pass4CodeGeneration.generate();
|
AsmProgram asmProgram = pass4CodeGeneration.generate();
|
||||||
Pass5NextJumpElimination pass5NextJumpElimination = new Pass5NextJumpElimination(asmProgram);
|
Pass5NextJumpElimination pass5NextJumpElimination = new Pass5NextJumpElimination(asmProgram);
|
||||||
pass5NextJumpElimination.optimize();
|
boolean asmOptimized = true;
|
||||||
|
while(asmOptimized) {
|
||||||
|
asmOptimized = pass5NextJumpElimination.optimize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
System.out.println("SYMBOLS");
|
System.out.println("SYMBOLS");
|
||||||
|
8
src/dk/camelot64/kickc/test/fibmem.kc
Normal file
8
src/dk/camelot64/kickc/test/fibmem.kc
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
byte[15] fibs = $1100;
|
||||||
|
fibs[0] = 0;
|
||||||
|
fibs[1] = 1;
|
||||||
|
byte i = 2;
|
||||||
|
while(i<15) {
|
||||||
|
fibs[i] = fibs[i-2]+fibs[i-1];
|
||||||
|
i = i + 1;
|
||||||
|
}
|
Reference in New Issue
Block a user