mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-04-06 15:41:05 +00:00
Initial working implementation of constants in the symbol table and ASM. Still needs to output const definitions (intelligently).
This commit is contained in:
parent
a553cb97c3
commit
6f2dfdbec3
@ -135,8 +135,10 @@ public class Compiler {
|
||||
public void pass2OptimizeSSA(Program program) {
|
||||
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
|
||||
optimizations.add(new Pass2CullEmptyBlocks(program));
|
||||
optimizations.add(new Pass2ConstantPropagation(program));
|
||||
optimizations.add(new Pass2ConstantAdditionElimination(program));
|
||||
optimizations.add(new Pass2ConstantIdentification(program));
|
||||
|
||||
//optimizations.add(new Pass2ConstantPropagation(program));
|
||||
//optimizations.add(new Pass2ConstantAdditionElimination(program));
|
||||
optimizations.add(new Pass2UnaryNotSimplification(program));
|
||||
optimizations.add(new Pass2AliasElimination(program));
|
||||
optimizations.add(new Pass2RedundantPhiElimination(program));
|
||||
@ -212,7 +214,7 @@ public class Compiler {
|
||||
|
||||
new Pass3VariableRegisterWeightAnalysis(program).findWeights();
|
||||
program.getLog().append("\nVARIABLE REGISTER WEIGHTS");
|
||||
program.getLog().append(program.getScope().getSymbolTableContents(program, Variable.class));
|
||||
program.getLog().append(program.getScope().toString(program, Variable.class));
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
TODO's for new Constant Solution
|
||||
- Live range overlap analysis of register combinations inside methods must also look at registers alive at all calls.
|
||||
- Examine why temp-vars are used in flipper.
|
||||
+ Live range overlap analysis of register combinations inside methods must also look at registers alive at all calls.
|
||||
+ Examine why temp-vars are used in flipper.
|
||||
- Examine why flipper is plotted in a wrong position on the screen.
|
||||
- Implement constants into the symbol table and support them in code.
|
||||
- Implement new constant consolidation steps.
|
||||
- Look at optimizing liverange.kc's ASM further - atm. there are to many copy-operations into unnecesary registers.
|
||||
+ Look at optimizing liverange.kc's ASM further - atm. there are to many copy-operations into unnecesary registers.
|
||||
+ In summin.asm the result of the 2nd sum() is clobbered twice during call to sum(). jsr sum, txa, lda #$d, ldx #$9, jsr sum
|
||||
+ Fix by introducing "effective alive vars" which includes alive vars at all calls to containing methods and using that during clobber check.
|
||||
+ In loopnest.asm x&y are used in both loops - the outer x&y are clobbered by the inner loop.
|
||||
- In voronoi.asm in render() x is clobbered during call to findcol().
|
||||
+ In voronoi.asm in render() x is clobbered during call to findcol().
|
||||
|
||||
|
||||
Features
|
||||
|
@ -33,7 +33,11 @@ public class AsmFragment {
|
||||
*/
|
||||
private String signature;
|
||||
|
||||
public AsmFragment(StatementConditionalJump conditionalJump, ControlFlowBlock block, Program program, ControlFlowGraph graph) {
|
||||
public AsmFragment(
|
||||
StatementConditionalJump conditionalJump,
|
||||
ControlFlowBlock block,
|
||||
Program program,
|
||||
ControlFlowGraph graph) {
|
||||
this.scope = program.getGraph().getBlockFromStatementIdx(conditionalJump.getIndex()).getScope();
|
||||
this.bindings = new LinkedHashMap<>();
|
||||
this.program = program;
|
||||
@ -45,7 +49,11 @@ public class AsmFragment {
|
||||
this.scope = program.getGraph().getBlockFromStatementIdx(assignment.getIndex()).getScope();
|
||||
this.bindings = new LinkedHashMap<>();
|
||||
this.program = program;
|
||||
setSignature(assignmentSignature(assignment.getlValue(), assignment.getrValue1(), assignment.getOperator(), assignment.getrValue2()));
|
||||
setSignature(assignmentSignature(
|
||||
assignment.getlValue(),
|
||||
assignment.getrValue1(),
|
||||
assignment.getOperator(),
|
||||
assignment.getrValue2()));
|
||||
}
|
||||
|
||||
public AsmFragment(LValue lValue, RValue rValue, Program program, ScopeRef scope) {
|
||||
@ -84,7 +92,10 @@ public class AsmFragment {
|
||||
if (assignment.getOperator() != null) {
|
||||
signature.append(getOperatorFragmentName(assignment.getOperator()));
|
||||
}
|
||||
signature.append(assignmentRightSideSignature(assignmentAlu.getrValue1(), assignmentAlu.getOperator(), assignmentAlu.getrValue2()));
|
||||
signature.append(assignmentRightSideSignature(
|
||||
assignmentAlu.getrValue1(),
|
||||
assignmentAlu.getOperator(),
|
||||
assignmentAlu.getrValue2()));
|
||||
return signature.toString();
|
||||
}
|
||||
|
||||
@ -114,7 +125,8 @@ public class AsmFragment {
|
||||
rValue2 instanceof ConstantInteger &&
|
||||
((ConstantInteger) rValue2).getNumber() == 1 &&
|
||||
operator != null &&
|
||||
(operator.getOperator().equals("-") || operator.getOperator().equals("+") || operator.getOperator().equals(">>") || operator.getOperator().equals("<<"))) {
|
||||
(operator.getOperator().equals("-") || operator.getOperator().equals("+") || operator.getOperator().equals(
|
||||
">>") || operator.getOperator().equals("<<"))) {
|
||||
signature.append("1");
|
||||
} else if (
|
||||
rValue2 instanceof ConstantInteger &&
|
||||
@ -128,7 +140,10 @@ public class AsmFragment {
|
||||
return signature.toString();
|
||||
}
|
||||
|
||||
private String conditionalJumpSignature(StatementConditionalJump conditionalJump, ControlFlowBlock block, ControlFlowGraph graph) {
|
||||
private String conditionalJumpSignature(
|
||||
StatementConditionalJump conditionalJump,
|
||||
ControlFlowBlock block,
|
||||
ControlFlowGraph graph) {
|
||||
StringBuilder signature = new StringBuilder();
|
||||
if (conditionalJump.getrValue1() != null) {
|
||||
signature.append(bind(conditionalJump.getrValue1()));
|
||||
@ -149,7 +164,9 @@ public class AsmFragment {
|
||||
ControlFlowBlock destinationBlock = graph.getBlock(destination);
|
||||
String destinationLabel;
|
||||
if (destinationBlock.hasPhiBlock()) {
|
||||
destinationLabel = (destinationBlock.getLabel().getLocalName() + "_from_" + block.getLabel().getLocalName()).replace('@', 'b').replace(':', '_');
|
||||
destinationLabel = (destinationBlock.getLabel().getLocalName() + "_from_" + block.getLabel().getLocalName()).replace(
|
||||
'@',
|
||||
'b').replace(':', '_');
|
||||
} else {
|
||||
destinationLabel = destination.getLocalName();
|
||||
}
|
||||
@ -237,19 +254,22 @@ public class AsmFragment {
|
||||
if (value instanceof VariableRef) {
|
||||
value = program.getScope().getVariable((VariableRef) value);
|
||||
}
|
||||
if (value instanceof ConstantRef) {
|
||||
value = program.getScope().getConstant((ConstantRef) value);
|
||||
}
|
||||
if (value instanceof Variable) {
|
||||
Registers.Register register = ((Variable) value).getAllocation();
|
||||
Variable variable = (Variable) value;
|
||||
Registers.Register register = variable.getAllocation();
|
||||
// Find value if it is already bound
|
||||
for (String name : bindings.keySet()) {
|
||||
Value bound = bindings.get(name);
|
||||
if(bound instanceof Variable) {
|
||||
if (bound instanceof Variable) {
|
||||
Registers.Register boundRegister = ((Variable) bound).getAllocation();
|
||||
if(boundRegister!=null && boundRegister.equals(register)) {
|
||||
if (boundRegister != null && boundRegister.equals(register)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new suitable name
|
||||
if (Registers.RegisterType.ZP_BYTE.equals(register.getType())) {
|
||||
String name = "zpby" + nextZpByteIdx++;
|
||||
@ -282,13 +302,31 @@ public class AsmFragment {
|
||||
} else if (Registers.RegisterType.REG_ALU_BYTE.equals(register.getType())) {
|
||||
throw new AluNotApplicableException();
|
||||
}
|
||||
} else if (value instanceof ConstantVar) {
|
||||
ConstantVar constantVar = (ConstantVar) value;
|
||||
SymbolType constType = constantVar.getType();
|
||||
if (SymbolTypeBasic.BYTE.equals(constType)) {
|
||||
String name = "coby" + nextConstByteIdx++;
|
||||
bindings.put(name, constantVar);
|
||||
return name;
|
||||
} else if (SymbolTypeBasic.WORD.equals(constType)) {
|
||||
String name = "cowo" + nextConstByteIdx++;
|
||||
bindings.put(name, constantVar);
|
||||
return name;
|
||||
} else if (constType instanceof SymbolTypePointer && SymbolTypeBasic.BYTE.equals(((SymbolTypePointer) constType).getElementType())) {
|
||||
String name = "cowo" + nextConstByteIdx++;
|
||||
bindings.put(name, constantVar);
|
||||
return name;
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled constant type " + constType);
|
||||
}
|
||||
} else if (value instanceof ConstantInteger) {
|
||||
ConstantInteger intValue = (ConstantInteger) value;
|
||||
if (SymbolTypeBasic.BYTE.equals(intValue.getType())) {
|
||||
if (SymbolTypeBasic.BYTE.equals(intValue.getType(program.getScope()))) {
|
||||
String name = "coby" + nextConstByteIdx++;
|
||||
bindings.put(name, value);
|
||||
return name;
|
||||
} else if (SymbolTypeBasic.WORD.equals(intValue.getType())) {
|
||||
} else if (SymbolTypeBasic.WORD.equals(intValue.getType(program.getScope()))) {
|
||||
String name = "cowo" + nextConstByteIdx++;
|
||||
bindings.put(name, value);
|
||||
return name;
|
||||
@ -316,17 +354,7 @@ public class AsmFragment {
|
||||
Variable boundVar = (Variable) boundValue;
|
||||
Registers.Register register = boundVar.getAllocation();
|
||||
if (register != null && register instanceof Registers.RegisterZp) {
|
||||
Scope varScope = boundVar.getScope();
|
||||
String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName();
|
||||
if (!varScope.getRef().equals(scope) && varScope.getRef().getFullName().length() > 0) {
|
||||
String param = varScope.getFullName() + "." + asmName.replace('@', 'b').replace(':', '_').replace("#", "_").replace("$","_");
|
||||
//param = ""+((Registers.RegisterZp) register).getZp();
|
||||
return new AsmParameter(param, true);
|
||||
} else {
|
||||
String param = asmName.replace('@', 'b').replace(':', '_').replace("#", "_").replace("$","_");
|
||||
//param = ""+((Registers.RegisterZp) register).getZp();
|
||||
return new AsmParameter(param, true);
|
||||
}
|
||||
return new AsmParameter(getAsmParameter(boundVar), true);
|
||||
} else {
|
||||
throw new RuntimeException("Register Type not implemented " + register);
|
||||
}
|
||||
@ -338,30 +366,90 @@ public class AsmFragment {
|
||||
if (pointerConst instanceof ConstantInteger) {
|
||||
ConstantInteger intPointer = (ConstantInteger) pointerConst;
|
||||
String param = String.format("$%x", intPointer.getNumber());
|
||||
return new AsmParameter(param, SymbolTypeBasic.BYTE.equals(intPointer.getType()));
|
||||
return new AsmParameter(param, SymbolTypeBasic.BYTE.equals(intPointer.getType(program.getScope())));
|
||||
} else {
|
||||
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
|
||||
}
|
||||
} else if (boundValue instanceof ConstantInteger) {
|
||||
ConstantInteger boundInt = (ConstantInteger) boundValue;
|
||||
if (boundInt.getType().equals(SymbolTypeBasic.BYTE)) {
|
||||
String param = String.format("$%x", boundInt.getNumber());
|
||||
return new AsmParameter(param, SymbolTypeBasic.BYTE.equals(boundInt.getType()));
|
||||
} else {
|
||||
String param = String.format("$%x", boundInt.getNumber());
|
||||
return new AsmParameter(param, SymbolTypeBasic.BYTE.equals(boundInt.getType()));
|
||||
}
|
||||
} else if (boundValue instanceof Constant) {
|
||||
Constant boundConst = (Constant) boundValue;
|
||||
return new AsmParameter(toAsm(boundConst), SymbolTypeBasic.BYTE.equals(boundConst.getType(program.getScope())));
|
||||
} else if (boundValue instanceof Label) {
|
||||
String param = ((Label) boundValue).getLocalName().replace('@', 'b').replace(':', '_').replace("$","_");
|
||||
String param = ((Label) boundValue).getLocalName().replace('@', 'b').replace(':', '_').replace("$", "_");
|
||||
return new AsmParameter(param, false);
|
||||
} else {
|
||||
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ASM parameter for a specific bound variable
|
||||
* @param boundVar The variable
|
||||
* @return The ASM parameter to use in the ASM code
|
||||
*/
|
||||
private String getAsmParameter(Variable boundVar) {
|
||||
Scope varScope = boundVar.getScope();
|
||||
String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName();
|
||||
return getAsmParameter(varScope, asmName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ASM parameter for a specific bound constant
|
||||
* @param boundVar The constant
|
||||
* @return The ASM parameter to use in the ASM code
|
||||
*/
|
||||
private String getAsmParameter(ConstantVar boundVar) {
|
||||
Scope varScope = boundVar.getScope();
|
||||
String asmName = boundVar.getLocalName(); // boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName();
|
||||
return getAsmParameter(varScope, asmName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ASM parameter for a specific bound constant/ variable
|
||||
* @param varScope The scope containing the var/const
|
||||
* @param asmName The ASM name of the variable (local name or specific ASM name).
|
||||
* @return The ASM parameter to use in the ASM code
|
||||
*/
|
||||
private String getAsmParameter(Scope varScope, String asmName) {
|
||||
if (!varScope.getRef().equals(scope) && varScope.getRef().getFullName().length() > 0) {
|
||||
String param = varScope.getFullName() + "." + asmName
|
||||
.replace('@', 'b')
|
||||
.replace(':', '_')
|
||||
.replace("#","_")
|
||||
.replace("$","_");
|
||||
//param = ""+((Registers.RegisterZp) register).getZp();
|
||||
return param;
|
||||
} else {
|
||||
String param = asmName.replace('@', 'b').replace(':', '_').replace("#", "_").replace("$", "_");
|
||||
//param = ""+((Registers.RegisterZp) register).getZp();
|
||||
return param;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ASM code for the constant
|
||||
* @param constant The constant
|
||||
* @return ASM code
|
||||
*/
|
||||
private String toAsm(Constant constant) {
|
||||
if (constant instanceof ConstantInteger) {
|
||||
return String.format("$%x", ((ConstantInteger) constant).getNumber());
|
||||
} else if (constant instanceof ConstantVar) {
|
||||
ConstantVar constantVar = (ConstantVar) constant;
|
||||
return getAsmParameter(constantVar);
|
||||
} else if (constant instanceof ConstantUnary) {
|
||||
ConstantUnary unary = (ConstantUnary) constant;
|
||||
return unary.getOperator().toString() + toAsm(unary.getOperand());
|
||||
} else if (constant instanceof ConstantBinary) {
|
||||
ConstantBinary binary = (ConstantBinary) constant;
|
||||
return toAsm(binary.getLeft()) + binary.getOperator().toString() + toAsm(binary.getRight());
|
||||
} else {
|
||||
throw new RuntimeException("Unknown constant type " + constant);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** A parameter of an ASM instruction from a bound value. */
|
||||
public static class AsmParameter {
|
||||
@ -384,7 +472,6 @@ public class AsmFragment {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate assembler code for the assembler fragment.
|
||||
*
|
||||
@ -435,7 +522,11 @@ public class AsmFragment {
|
||||
Asm6502Parser.ParamModeContext paramModeCtx = ctx.paramMode();
|
||||
AsmInstruction instruction;
|
||||
if (paramModeCtx == null) {
|
||||
AsmInstructionType type = AsmInstructionSet.getInstructionType(ctx.MNEMONIC().getText(), AsmAddressingMode.NON, null, false);
|
||||
AsmInstructionType type = AsmInstructionSet.getInstructionType(
|
||||
ctx.MNEMONIC().getText(),
|
||||
AsmAddressingMode.NON,
|
||||
null,
|
||||
false);
|
||||
instruction = new AsmInstruction(type, null);
|
||||
} else {
|
||||
instruction = (AsmInstruction) this.visit(paramModeCtx);
|
||||
@ -483,11 +574,18 @@ public class AsmFragment {
|
||||
return createAsmInstruction(ctx, ctx.expr(), AsmAddressingMode.IND);
|
||||
}
|
||||
|
||||
private AsmInstruction createAsmInstruction(Asm6502Parser.ParamModeContext ctx, Asm6502Parser.ExprContext exprCtx, AsmAddressingMode addressingMode) {
|
||||
private AsmInstruction createAsmInstruction(
|
||||
Asm6502Parser.ParamModeContext ctx,
|
||||
Asm6502Parser.ExprContext exprCtx,
|
||||
AsmAddressingMode addressingMode) {
|
||||
Asm6502Parser.InstructionContext instructionCtx = (Asm6502Parser.InstructionContext) ctx.getParent();
|
||||
String mnemonic = instructionCtx.MNEMONIC().getSymbol().getText();
|
||||
AsmParameter parameter = (AsmParameter) this.visit(exprCtx);
|
||||
AsmInstructionType type = AsmInstructionSet.getInstructionType(mnemonic, addressingMode, parameter.getParam(), parameter.isZp());
|
||||
AsmInstructionType type = AsmInstructionSet.getInstructionType(
|
||||
mnemonic,
|
||||
addressingMode,
|
||||
parameter.getParam(),
|
||||
parameter.isZp());
|
||||
if (type == null) {
|
||||
throw new RuntimeException("Error in " + signature + ".asm line " + ctx.getStart().getLine() + " - Instruction type unknown " + mnemonic + " " + addressingMode + " " + parameter);
|
||||
}
|
||||
|
@ -3,4 +3,6 @@ package dk.camelot64.kickc.icl;
|
||||
/** SSA form constant value */
|
||||
public interface Constant extends RValue {
|
||||
|
||||
SymbolType getType(ProgramScope scope);
|
||||
|
||||
}
|
||||
|
50
src/main/java/dk/camelot64/kickc/icl/ConstantBinary.java
Normal file
50
src/main/java/dk/camelot64/kickc/icl/ConstantBinary.java
Normal file
@ -0,0 +1,50 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import dk.camelot64.kickc.passes.Pass1TypeInference;
|
||||
|
||||
/** A constant defined by a binary operator applied to two constants */
|
||||
public class ConstantBinary implements ConstantValue {
|
||||
|
||||
/** The left constant operand. */
|
||||
private Constant left;
|
||||
|
||||
/** The operator, */
|
||||
private Operator operator;
|
||||
|
||||
/** The right constant operand. */
|
||||
private Constant right;
|
||||
|
||||
public ConstantBinary(Constant left, Operator operator, Constant right) {
|
||||
this.left = left;
|
||||
this.operator = operator;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public Operator getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public Constant getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public Constant getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType(ProgramScope scope) {
|
||||
return Pass1TypeInference.inferType(left.getType(scope), operator, right.getType(scope));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Program program) {
|
||||
return left.toString(program)+operator.toString()+right.toString(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
}
|
||||
|
||||
}
|
@ -3,7 +3,7 @@ package dk.camelot64.kickc.icl;
|
||||
/**
|
||||
* SSA form constant integer value
|
||||
*/
|
||||
public class ConstantBool implements Constant {
|
||||
public class ConstantBool implements ConstantValue {
|
||||
|
||||
private Boolean value;
|
||||
|
||||
@ -11,6 +11,11 @@ public class ConstantBool implements Constant {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType(ProgramScope scope) {
|
||||
return SymbolTypeBasic.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
|
@ -3,7 +3,7 @@ package dk.camelot64.kickc.icl;
|
||||
/**
|
||||
* SSA form constant integer value
|
||||
*/
|
||||
public class ConstantDouble implements Constant {
|
||||
public class ConstantDouble implements ConstantValue {
|
||||
|
||||
private Double number;
|
||||
|
||||
@ -11,6 +11,11 @@ public class ConstantDouble implements Constant {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType(ProgramScope scope) {
|
||||
return SymbolTypeBasic.DOUBLE;
|
||||
}
|
||||
|
||||
public Double getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
@ -4,10 +4,8 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* SSA form constant integer value
|
||||
*/
|
||||
public class ConstantInteger implements Constant {
|
||||
/** SSA form constant integer value */
|
||||
public class ConstantInteger implements ConstantValue {
|
||||
|
||||
private Integer number;
|
||||
|
||||
@ -22,6 +20,10 @@ public class ConstantInteger implements Constant {
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public SymbolType getType(ProgramScope scope) {
|
||||
return getType();
|
||||
}
|
||||
|
||||
public SymbolType getType() {
|
||||
SymbolType type;
|
||||
if (getNumber() < 256) {
|
||||
@ -42,7 +44,7 @@ public class ConstantInteger implements Constant {
|
||||
if (program == null) {
|
||||
return Integer.toString(number);
|
||||
} else {
|
||||
return "(" + getType().getTypeName() + ") " + Integer.toString(number);
|
||||
return "(" + getType(program.getScope()).getTypeName() + ") " + Integer.toString(number);
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,9 +52,7 @@ public class ConstantInteger implements Constant {
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ConstantInteger that = (ConstantInteger) o;
|
||||
|
||||
return number != null ? number.equals(that.number) : that.number == null;
|
||||
}
|
||||
|
||||
|
25
src/main/java/dk/camelot64/kickc/icl/ConstantRef.java
Normal file
25
src/main/java/dk/camelot64/kickc/icl/ConstantRef.java
Normal file
@ -0,0 +1,25 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/** A reference to a named Constant (in the symbol table) */
|
||||
public class ConstantRef extends SymbolRef implements ConstantValue {
|
||||
|
||||
@JsonCreator
|
||||
public ConstantRef(
|
||||
@JsonProperty("fullName") String fullName) {
|
||||
super(fullName);
|
||||
}
|
||||
|
||||
public ConstantRef(ConstantVar constantVar) {
|
||||
super(constantVar.getFullName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType(ProgramScope scope) {
|
||||
ConstantVar constant = scope.getConstant(this);
|
||||
return constant.getType(scope);
|
||||
}
|
||||
|
||||
}
|
@ -3,7 +3,7 @@ package dk.camelot64.kickc.icl;
|
||||
/**
|
||||
* SSA form constant integer value
|
||||
*/
|
||||
public class ConstantString implements Constant {
|
||||
public class ConstantString implements ConstantValue {
|
||||
|
||||
private String value;
|
||||
|
||||
@ -11,6 +11,11 @@ public class ConstantString implements Constant {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType(ProgramScope scope) {
|
||||
return SymbolTypeBasic.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
|
67
src/main/java/dk/camelot64/kickc/icl/ConstantUnary.java
Normal file
67
src/main/java/dk/camelot64/kickc/icl/ConstantUnary.java
Normal file
@ -0,0 +1,67 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import dk.camelot64.kickc.passes.Pass1TypeInference;
|
||||
|
||||
/** A constant defined by a unary operator appied to another constant */
|
||||
public class ConstantUnary implements ConstantValue {
|
||||
|
||||
/** The operator, */
|
||||
private Operator operator;
|
||||
|
||||
/** The constant operand. */
|
||||
private Constant operand;
|
||||
|
||||
public ConstantUnary(Operator operator, Constant operand) {
|
||||
this.operator = operator;
|
||||
this.operand = operand;
|
||||
}
|
||||
|
||||
public Operator getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public Constant getOperand() {
|
||||
return operand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType(ProgramScope scope) {
|
||||
return Pass1TypeInference.inferType(operator, operand.getType(scope));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstantUnary that = (ConstantUnary) o;
|
||||
|
||||
if (!operator.equals(that.operator)) {
|
||||
return false;
|
||||
}
|
||||
return operand.equals(that.operand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = operator.hashCode();
|
||||
result = 31 * result + operand.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Program program) {
|
||||
return operator.toString()+operand.toString(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
}
|
||||
|
||||
|
||||
}
|
6
src/main/java/dk/camelot64/kickc/icl/ConstantValue.java
Normal file
6
src/main/java/dk/camelot64/kickc/icl/ConstantValue.java
Normal file
@ -0,0 +1,6 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/** A constant value. The value might be calculated through a constant expression. */
|
||||
public interface ConstantValue extends Constant {
|
||||
|
||||
}
|
127
src/main/java/dk/camelot64/kickc/icl/ConstantVar.java
Normal file
127
src/main/java/dk/camelot64/kickc/icl/ConstantVar.java
Normal file
@ -0,0 +1,127 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/** A named constant or a variable that has been inferred to be constant in the symbol table */
|
||||
public class ConstantVar implements Constant, Symbol {
|
||||
|
||||
/** The name of the variable. */
|
||||
private String name;
|
||||
|
||||
/** The scope containing the variable */
|
||||
@JsonIgnore
|
||||
private Scope scope;
|
||||
|
||||
/** The type of the variable. VAR means tha type is unknown, and has not been inferred yet. */
|
||||
private SymbolType type;
|
||||
|
||||
/** The value of the constant. */
|
||||
private ConstantValue value;
|
||||
|
||||
public ConstantVar(String name, Scope scope, SymbolType type, ConstantValue value) {
|
||||
this.name = name;
|
||||
this.scope = scope;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType(ProgramScope scope) {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullName() {
|
||||
return Scope.getFullName(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scope getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeDepth() {
|
||||
if(scope==null) {
|
||||
return 0;
|
||||
} else {
|
||||
return scope.getScopeDepth()+1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScope(Scope scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public ConstantValue getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(ConstantValue value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ConstantRef getRef() {
|
||||
return new ConstantRef(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString(Program program) {
|
||||
String s = new StringBuilder()
|
||||
.append("(")
|
||||
.append("const"+" ")
|
||||
.append(type.getTypeName())
|
||||
.append(") ")
|
||||
.append(getFullName()).toString();
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstantVar that = (ConstantVar) o;
|
||||
|
||||
if (name != null ? !name.equals(that.name) : that.name != null) {
|
||||
return false;
|
||||
}
|
||||
if (scope != null ? !scope.equals(that.scope) : that.scope != null) {
|
||||
return false;
|
||||
}
|
||||
if (type != null ? !type.equals(that.type) : that.type != null) {
|
||||
return false;
|
||||
}
|
||||
return value != null ? value.equals(that.value) : that.value == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name != null ? name.hashCode() : 0;
|
||||
result = 31 * result + (scope != null ? scope.hashCode() : 0);
|
||||
result = 31 * result + (type != null ? type.hashCode() : 0);
|
||||
result = 31 * result + (value != null ? value.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -27,9 +27,7 @@ public class Operator {
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Operator operator1 = (Operator) o;
|
||||
|
||||
return operator != null ? operator.equals(operator1.operator) : operator1.operator == null;
|
||||
}
|
||||
|
||||
|
@ -71,11 +71,11 @@ public class Procedure extends Scope {
|
||||
return super.getFullName();
|
||||
}
|
||||
|
||||
public String getSymbolTableContents(Program program, Class symbolClass) {
|
||||
public String toString(Program program, Class symbolClass) {
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append(toString(program));
|
||||
res.append("\n");
|
||||
res.append(super.getSymbolTableContents(program, symbolClass));
|
||||
res.append(super.toString(program, symbolClass));
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
|
@ -30,14 +30,14 @@ public class ProgramScope extends Scope {
|
||||
|
||||
@JsonIgnore
|
||||
public String getSymbolTableContents(Program program) {
|
||||
return getSymbolTableContents(program, null);
|
||||
return toString(program, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbolTableContents(Program program, Class symbolClass) {
|
||||
public String toString(Program program, Class symbolClass) {
|
||||
LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = program.getLiveRangeEquivalenceClassSet();
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append(super.getSymbolTableContents(program, symbolClass));
|
||||
out.append(super.toString(program, symbolClass));
|
||||
if(liveRangeEquivalenceClassSet!=null) {
|
||||
out.append("\n");
|
||||
for (LiveRangeEquivalenceClass liveRangeEquivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
|
||||
|
@ -26,7 +26,7 @@ public abstract class Scope implements Symbol {
|
||||
|
||||
@JsonCreator
|
||||
public Scope(
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("symbols") HashMap<String, Symbol> symbols,
|
||||
@JsonProperty("intermediateVarCount") int intermediateVarCount,
|
||||
@JsonProperty("intermediateLabelCount") int intermediateLabelCount) {
|
||||
@ -136,8 +136,8 @@ public abstract class Scope implements Symbol {
|
||||
}
|
||||
} else {
|
||||
Symbol symbol = symbols.get(name);
|
||||
if(symbol==null) {
|
||||
if(parentScope!=null) {
|
||||
if (symbol == null) {
|
||||
if (parentScope != null) {
|
||||
symbol = parentScope.getSymbol(name);
|
||||
}
|
||||
}
|
||||
@ -153,6 +153,14 @@ public abstract class Scope implements Symbol {
|
||||
return getVariable(variableRef.getFullName());
|
||||
}
|
||||
|
||||
public ConstantVar getConstant(String name) {
|
||||
return (ConstantVar) getSymbol(name);
|
||||
}
|
||||
|
||||
public ConstantVar getConstant(ConstantRef constantRef) {
|
||||
return getConstant(constantRef.getFullName());
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public Collection<Variable> getAllVariables(boolean includeSubScopes) {
|
||||
Collection<Variable> vars = new ArrayList<>();
|
||||
@ -160,7 +168,7 @@ public abstract class Scope implements Symbol {
|
||||
if (symbol instanceof Variable) {
|
||||
vars.add((Variable) symbol);
|
||||
}
|
||||
if(includeSubScopes && symbol instanceof Scope) {
|
||||
if (includeSubScopes && symbol instanceof Scope) {
|
||||
Scope subScope = (Scope) symbol;
|
||||
vars.addAll(subScope.getAllVariables(true));
|
||||
}
|
||||
@ -180,7 +188,7 @@ public abstract class Scope implements Symbol {
|
||||
for (Symbol symbol : symbols.values()) {
|
||||
if (symbol instanceof Scope) {
|
||||
scopes.add((Scope) symbol);
|
||||
if(includeSubScopes) {
|
||||
if (includeSubScopes) {
|
||||
Scope subScope = (Scope) symbol;
|
||||
scopes.addAll(subScope.getAllScopes(true));
|
||||
}
|
||||
@ -192,7 +200,7 @@ public abstract class Scope implements Symbol {
|
||||
public Collection<Procedure> getAllProcedures(boolean includeSubScopes) {
|
||||
Collection<Procedure> procedures = new ArrayList<>();
|
||||
for (Scope scope : getAllScopes(includeSubScopes)) {
|
||||
if(scope instanceof Procedure) {
|
||||
if (scope instanceof Procedure) {
|
||||
procedures.add((Procedure) scope);
|
||||
}
|
||||
}
|
||||
@ -241,12 +249,12 @@ public abstract class Scope implements Symbol {
|
||||
}
|
||||
|
||||
public Scope getScope(ScopeRef scopeRef) {
|
||||
if(scopeRef.getFullName().equals("") && this instanceof ProgramScope) {
|
||||
if (scopeRef.getFullName().equals("") && this instanceof ProgramScope) {
|
||||
// Special case for the outer program scope
|
||||
return this;
|
||||
}
|
||||
Symbol symbol = getSymbol(scopeRef);
|
||||
if(symbol instanceof Scope) {
|
||||
if (symbol instanceof Scope) {
|
||||
return (Scope) symbol;
|
||||
} else {
|
||||
return null;
|
||||
@ -255,11 +263,11 @@ public abstract class Scope implements Symbol {
|
||||
|
||||
|
||||
public Procedure getProcedure(ProcedureRef ref) {
|
||||
return (Procedure) getSymbol(ref);
|
||||
return (Procedure) getSymbol(ref);
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public String getSymbolTableContents(Program program, Class symbolClass) {
|
||||
public String toString(Program program, Class symbolClass) {
|
||||
VariableRegisterWeights registerWeights = program.getVariableRegisterWeights();
|
||||
StringBuilder res = new StringBuilder();
|
||||
Set<String> names = symbols.keySet();
|
||||
@ -268,26 +276,32 @@ public abstract class Scope implements Symbol {
|
||||
for (String name : sortedNames) {
|
||||
Symbol symbol = symbols.get(name);
|
||||
if (symbol instanceof Scope) {
|
||||
res.append(((Scope) symbol).getSymbolTableContents(program, symbolClass));
|
||||
res.append(((Scope) symbol).toString(program, symbolClass));
|
||||
} else {
|
||||
if (symbolClass == null || symbolClass.isInstance(symbol)) {
|
||||
res.append(symbol.toString(program));
|
||||
if (symbol instanceof Variable) {
|
||||
String asmName = ((Variable) symbol).getAsmName();
|
||||
if(asmName!=null) {
|
||||
res.append(" "+asmName);
|
||||
Variable var = (Variable) symbol;
|
||||
String asmName = var.getAsmName();
|
||||
if (asmName != null) {
|
||||
res.append(" " + asmName);
|
||||
}
|
||||
Registers.Register register = ((Variable) symbol).getAllocation();
|
||||
Registers.Register register = var.getAllocation();
|
||||
if (register != null) {
|
||||
res.append(" " + register);
|
||||
}
|
||||
}
|
||||
if (symbol instanceof Variable && registerWeights != null) {
|
||||
Double weight = registerWeights.getWeight(((Variable) symbol).getRef());
|
||||
Variable var = (Variable) symbol;
|
||||
Double weight = registerWeights.getWeight(var.getRef());
|
||||
if (weight != null) {
|
||||
res.append(" " + weight);
|
||||
}
|
||||
}
|
||||
if (symbol instanceof ConstantVar) {
|
||||
ConstantVar constantVar = (ConstantVar) symbol;
|
||||
res.append(" = " + constantVar.getValue().toString(program));
|
||||
}
|
||||
res.append("\n");
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ public class SymbolTypeBasic implements SymbolType {
|
||||
public static final SymbolTypeBasic WORD = new SymbolTypeBasic("word");
|
||||
public static final SymbolTypeBasic STRING = new SymbolTypeBasic("string");
|
||||
public static final SymbolTypeBasic BOOLEAN = new SymbolTypeBasic("boolean");
|
||||
public static final SymbolTypeBasic DOUBLE = new SymbolTypeBasic("double");
|
||||
// A label
|
||||
public static final SymbolTypeBasic LABEL = new SymbolTypeBasic("label");
|
||||
// Void type.
|
||||
|
@ -24,8 +24,8 @@ public abstract class Variable implements Symbol {
|
||||
/** A short name used for the variable in ASM code. If possible variable names of ZP variables are shortened in ASM code. This is possible, when all versions of the var use the same register. */
|
||||
private String asmName;
|
||||
|
||||
/** If the variable is a constant this is the constant value. If null the variable is not considered constant.*/
|
||||
private Constant constant;
|
||||
/** Speciies that the variableis declared a constant. It willb replaced by a ConstantVar when possible. */
|
||||
private boolean declaredConstant;
|
||||
|
||||
public Variable(String name, Scope scope, SymbolType type) {
|
||||
this.name = name;
|
||||
@ -93,14 +93,6 @@ public abstract class Variable implements Symbol {
|
||||
this.asmName = asmName;
|
||||
}
|
||||
|
||||
public Constant getConstant() {
|
||||
return constant;
|
||||
}
|
||||
|
||||
public void setConstant(Constant constant) {
|
||||
this.constant = constant;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public abstract boolean isVersioned();
|
||||
|
||||
@ -126,30 +118,12 @@ public abstract class Variable implements Symbol {
|
||||
return new VariableRef(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Variable variable = (Variable) o;
|
||||
if (inferredType != variable.inferredType) return false;
|
||||
if (name != null ? !name.equals(variable.name) : variable.name != null) return false;
|
||||
if (scope != null ? !scope.equals(variable.scope) : variable.scope != null) return false;
|
||||
if (type != null ? !type.equals(variable.type) : variable.type != null) return false;
|
||||
if (allocation != null ? !allocation.equals(variable.allocation) : variable.allocation != null) return false;
|
||||
if (asmName != null ? !asmName.equals(variable.asmName) : variable.asmName != null) return false;
|
||||
return constant != null ? constant.equals(variable.constant) : variable.constant == null;
|
||||
public boolean isDeclaredConstant() {
|
||||
return declaredConstant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name != null ? name.hashCode() : 0;
|
||||
result = 31 * result + (scope != null ? scope.hashCode() : 0);
|
||||
result = 31 * result + (type != null ? type.hashCode() : 0);
|
||||
result = 31 * result + (inferredType ? 1 : 0);
|
||||
result = 31 * result + (allocation != null ? allocation.hashCode() : 0);
|
||||
result = 31 * result + (asmName != null ? asmName.hashCode() : 0);
|
||||
result = 31 * result + (constant != null ? constant.hashCode() : 0);
|
||||
return result;
|
||||
public void setDeclaredConstant(boolean declaredConstant) {
|
||||
this.declaredConstant = declaredConstant;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,4 +142,43 @@ public abstract class Variable implements Symbol {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Variable variable = (Variable) o;
|
||||
|
||||
if (inferredType != variable.inferredType) {
|
||||
return false;
|
||||
}
|
||||
if (name != null ? !name.equals(variable.name) : variable.name != null) {
|
||||
return false;
|
||||
}
|
||||
if (scope != null ? !scope.equals(variable.scope) : variable.scope != null) {
|
||||
return false;
|
||||
}
|
||||
if (type != null ? !type.equals(variable.type) : variable.type != null) {
|
||||
return false;
|
||||
}
|
||||
if (allocation != null ? !allocation.equals(variable.allocation) : variable.allocation != null) {
|
||||
return false;
|
||||
}
|
||||
return asmName != null ? asmName.equals(variable.asmName) : variable.asmName == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name != null ? name.hashCode() : 0;
|
||||
result = 31 * result + (scope != null ? scope.hashCode() : 0);
|
||||
result = 31 * result + (type != null ? type.hashCode() : 0);
|
||||
result = 31 * result + (inferredType ? 1 : 0);
|
||||
result = 31 * result + (allocation != null ? allocation.hashCode() : 0);
|
||||
result = 31 * result + (asmName != null ? asmName.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class ParseTreeConstantEvaluator extends KickCBaseVisitor<Constant> {
|
||||
Constant sub = visit(ctx.expr());
|
||||
String op = ((TerminalNode)ctx.getChild(0)).getSymbol().getText();
|
||||
Operator operator = new Operator(op);
|
||||
return Pass2ConstantPropagation.calculateUnary(operator, sub);
|
||||
return calculateUnary(operator, sub);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -88,17 +88,102 @@ public class ParseTreeConstantEvaluator extends KickCBaseVisitor<Constant> {
|
||||
Constant right = this.visit(ctx.expr(1));
|
||||
String op = ((TerminalNode)ctx.getChild(1)).getSymbol().getText();
|
||||
Operator operator = new Operator(op);
|
||||
return Pass2ConstantPropagation.calculateBinary(operator, left, right);
|
||||
return calculateBinary(operator, left, right);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Thrown if the expression is not a constant. */
|
||||
public static class NotConstantException extends RuntimeException {
|
||||
|
||||
public NotConstantException() {
|
||||
}
|
||||
}
|
||||
|
||||
static Constant calculateBinary(Operator operator, Constant c1, Constant c2) {
|
||||
switch (operator.getOperator()) {
|
||||
case "-": {
|
||||
if (c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
|
||||
return new ConstantInteger(getInteger(c1) - getInteger(c2));
|
||||
} else {
|
||||
return new ConstantDouble(getDouble(c1) - getDouble(c2));
|
||||
}
|
||||
}
|
||||
case "+": {
|
||||
if (c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
|
||||
return new ConstantInteger(getInteger(c1) + getInteger(c2));
|
||||
} else {
|
||||
return new ConstantDouble(getDouble(c1) + getDouble(c2));
|
||||
}
|
||||
}
|
||||
case "*": {
|
||||
if (c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
|
||||
return new ConstantInteger(getInteger(c1) * getInteger(c2));
|
||||
} else {
|
||||
return new ConstantDouble(getDouble(c1) * getDouble(c2));
|
||||
}
|
||||
}
|
||||
case "/": {
|
||||
if (c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
|
||||
return new ConstantInteger(getInteger(c1) / getInteger(c2));
|
||||
} else {
|
||||
return new ConstantDouble(getDouble(c1) / getDouble(c2));
|
||||
}
|
||||
}
|
||||
case "*idx": {
|
||||
// Cannot be directly propagated
|
||||
return null;
|
||||
}
|
||||
default:
|
||||
throw new RuntimeException("Unhandled Binary Operator " + operator.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer getInteger(Constant constant) {
|
||||
if (constant instanceof ConstantInteger) {
|
||||
return ((ConstantInteger) constant).getNumber();
|
||||
} else {
|
||||
throw new RuntimeException("Type Mismatch. Constant is not an integer number " + constant);
|
||||
}
|
||||
}
|
||||
|
||||
private static Double getDouble(Constant constant) {
|
||||
if (constant instanceof ConstantDouble) {
|
||||
return ((ConstantDouble) constant).getNumber();
|
||||
} else if (constant instanceof ConstantInteger) {
|
||||
return ((ConstantInteger) constant).getNumber().doubleValue();
|
||||
} else {
|
||||
throw new RuntimeException("Type Mismatch. Constant is not a number " + constant);
|
||||
}
|
||||
}
|
||||
|
||||
public static Constant calculateUnary(Operator operator, Constant c) {
|
||||
switch (operator.getOperator()) {
|
||||
case "-": {
|
||||
if (c instanceof ConstantInteger) {
|
||||
ConstantInteger cInt = (ConstantInteger) c;
|
||||
return new ConstantInteger(-cInt.getNumber());
|
||||
} else if (c instanceof ConstantDouble) {
|
||||
ConstantDouble cDoub = (ConstantDouble) c;
|
||||
return new ConstantDouble(-cDoub.getNumber());
|
||||
} else {
|
||||
throw new RuntimeException("Type mismatch. Unary Minus cannot handle value " + c);
|
||||
}
|
||||
}
|
||||
case "+": {
|
||||
return c;
|
||||
}
|
||||
case "++": {
|
||||
ConstantInteger cInt = (ConstantInteger) c;
|
||||
return new ConstantInteger(cInt.getNumber()+1);
|
||||
}
|
||||
case "--": {
|
||||
ConstantInteger cInt = (ConstantInteger) c;
|
||||
return new ConstantInteger(cInt.getNumber()-1);
|
||||
}
|
||||
case "*": { // pointer dereference
|
||||
return null;
|
||||
}
|
||||
default:
|
||||
throw new RuntimeException("Unhandled Unary Operator " + operator.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -330,13 +330,13 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
|
||||
@Override
|
||||
public Void visitStmtDeclaration(KickCParser.StmtDeclarationContext ctx) {
|
||||
if (ctx.getChild(0).getText().equals("const")) {
|
||||
program.getLog().append("Const!" + ctx.getText());
|
||||
}
|
||||
SymbolType type = (SymbolType) visit(ctx.typeDecl());
|
||||
String varName = ctx.NAME().getText();
|
||||
KickCParser.InitializerContext initializer = ctx.initializer();
|
||||
VariableUnversioned lValue = getCurrentSymbols().addVariable(varName, type);
|
||||
if (ctx.getChild(0).getText().equals("const")) {
|
||||
lValue.setDeclaredConstant(true);
|
||||
}
|
||||
if (initializer != null) {
|
||||
addInitialAssignment(initializer, lValue);
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ public class Pass1TypeInference {
|
||||
}
|
||||
}
|
||||
|
||||
private SymbolType inferType(Operator operator, SymbolType subType) {
|
||||
public static SymbolType inferType(Operator operator, SymbolType subType) {
|
||||
if(operator==null) {
|
||||
return subType;
|
||||
}
|
||||
@ -88,7 +88,7 @@ public class Pass1TypeInference {
|
||||
}
|
||||
}
|
||||
|
||||
private SymbolType inferType(SymbolType type1, Operator operator, SymbolType type2) {
|
||||
public static SymbolType inferType(SymbolType type1, Operator operator, SymbolType type2) {
|
||||
String op = operator.getOperator();
|
||||
switch (op) {
|
||||
case "==":
|
||||
@ -166,7 +166,7 @@ public class Pass1TypeInference {
|
||||
type = rSymbol.getType();
|
||||
} else if (rValue instanceof ConstantInteger) {
|
||||
ConstantInteger rInt = (ConstantInteger) rValue;
|
||||
return rInt.getType();
|
||||
return rInt.getType(programScope);
|
||||
} else if (rValue instanceof ConstantString) {
|
||||
type = SymbolTypeBasic.STRING;
|
||||
} else if (rValue instanceof ConstantBool) {
|
||||
|
@ -28,6 +28,7 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
|
||||
HashSet<Symbol> tableSymbols = getAllSymbols(getSymbols());
|
||||
for (Symbol tableSymbol : tableSymbols) {
|
||||
if(tableSymbol instanceof VariableUnversioned) continue;
|
||||
if(tableSymbol instanceof ConstantVar) continue;
|
||||
Symbol codeSymbol = null;
|
||||
String codeSymbolFullName = tableSymbol.getFullName();
|
||||
for (Symbol symbol : codeSymbols) {
|
||||
|
@ -0,0 +1,150 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.icl.*;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** Compiler Pass propagating constants in expressions eliminating constant variables */
|
||||
public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
|
||||
public Pass2ConstantIdentification(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagate constants, replacing variables with constants where possible.
|
||||
* @return true optimization was performed. false if no optimization was possible.
|
||||
*/
|
||||
@Override
|
||||
public boolean optimize() {
|
||||
Map<VariableRef, ConstantValue> constants = findConstantVariables();
|
||||
LinkedHashMap<VariableRef, RValue> constAliases = new LinkedHashMap<>();
|
||||
// Update symbol table with the constant value
|
||||
for (VariableRef constRef : constants.keySet()) {
|
||||
Variable variable = getProgram().getScope().getVariable(constRef);
|
||||
ConstantValue constVal = constants.get(constRef);
|
||||
Scope constScope = variable.getScope();
|
||||
ConstantVar constantVar = new ConstantVar(
|
||||
variable.getName(),
|
||||
constScope,
|
||||
variable.getType(),
|
||||
constVal);
|
||||
constScope.remove(variable);
|
||||
constScope.add(constantVar);
|
||||
constAliases.put(constRef, constantVar.getRef());
|
||||
getLog().append("Constant " + constantVar.toString(getProgram()));
|
||||
}
|
||||
// Remove assignments to constants in the code
|
||||
removeAssignments(constants.keySet());
|
||||
// Replace VariableRef's with ConstantRef's
|
||||
replaceVariables(constAliases);
|
||||
return constants.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find variables that have constant values.
|
||||
* @return Map from Variable to the Constant value
|
||||
*/
|
||||
private Map<VariableRef, ConstantValue> findConstantVariables() {
|
||||
final Map<VariableRef, ConstantValue> constants = new LinkedHashMap<>();
|
||||
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitAssignment(StatementAssignment assignment) {
|
||||
if (assignment.getlValue() instanceof VariableRef) {
|
||||
VariableRef variable = (VariableRef) assignment.getlValue();
|
||||
if (assignment.getrValue1() == null && getConstant(assignment.getrValue2()) != null) {
|
||||
if (assignment.getOperator() == null) {
|
||||
// Constant assignment
|
||||
ConstantValue constant = getConstant(assignment.getrValue2());
|
||||
constants.put(variable, constant);
|
||||
} else {
|
||||
// Constant unary expression
|
||||
ConstantValue constant = createUnary(assignment.getOperator(), getConstant(assignment.getrValue2()));
|
||||
if (constant != null) {
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
}
|
||||
} else if (getConstant(assignment.getrValue1()) != null && getConstant(assignment.getrValue2()) != null) {
|
||||
// Constant binary expression
|
||||
ConstantValue constant = createBinary(
|
||||
getConstant(assignment.getrValue1()),
|
||||
assignment.getOperator(),
|
||||
getConstant(assignment.getrValue2()));
|
||||
if (constant != null) {
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitPhiBlock(StatementPhiBlock phi) {
|
||||
for (StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
|
||||
if (phiVariable.getValues().size() == 1) {
|
||||
StatementPhiBlock.PhiRValue phiRValue = phiVariable.getValues().get(0);
|
||||
if (getConstant(phiRValue.getrValue()) != null) {
|
||||
VariableRef variable = phiVariable.getVariable();
|
||||
ConstantValue constant = getConstant(phiRValue.getrValue());
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
visitor.visitGraph(getGraph());
|
||||
return constants;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the rValue is a known constant return the constant value.
|
||||
*
|
||||
* @param rValue The rValue to examine
|
||||
* @return The constant value. null is the rValue is not a known constant.
|
||||
*/
|
||||
private ConstantValue getConstant(RValue rValue) {
|
||||
if (rValue instanceof ConstantValue) {
|
||||
return (ConstantValue) rValue;
|
||||
} else if (rValue instanceof ConstantVar) {
|
||||
ConstantVar constantVar = (ConstantVar) rValue;
|
||||
return constantVar.getRef();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
static ConstantValue createBinary(Constant c1, Operator operator, Constant c2) {
|
||||
switch (operator.getOperator()) {
|
||||
case "-":
|
||||
case "+":
|
||||
case "*":
|
||||
case "/":
|
||||
return new ConstantBinary(c1, operator, c2);
|
||||
case "*idx":
|
||||
// Pointer dereference - not constant
|
||||
return null;
|
||||
default:
|
||||
throw new RuntimeException("Unhandled Binary Operator " + operator.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
static ConstantValue createUnary(Operator operator, Constant c) {
|
||||
switch (operator.getOperator()) {
|
||||
case "-":
|
||||
case "+":
|
||||
case "++":
|
||||
case "--":
|
||||
return new ConstantUnary(operator, c);
|
||||
case "*": { // pointer dereference - not constant
|
||||
return null;
|
||||
}
|
||||
default:
|
||||
throw new RuntimeException("Unhandled Unary Operator " + operator.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.icl.*;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** Compiler Pass propagating constants in expressions eliminating constant variables */
|
||||
public class Pass2ConstantPropagation extends Pass2SsaOptimization {
|
||||
|
||||
public Pass2ConstantPropagation(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagate constants, replacing variables with constants where possible.
|
||||
* @return true optimization was performed. false if no optimization was possible.
|
||||
*/
|
||||
@Override
|
||||
public boolean optimize() {
|
||||
final Map<VariableRef, Constant> constants = findConstantVariables();
|
||||
for (VariableRef constantVar : constants.keySet()) {
|
||||
Constant constantValue = constants.get(constantVar);
|
||||
getLog().append("Constant " + constantVar.toString(getProgram()) + " " + constantValue.toString(getProgram()));
|
||||
}
|
||||
removeAssignments(constants.keySet());
|
||||
deleteVariables(constants.keySet());
|
||||
replaceVariables(constants);
|
||||
return constants.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find variables that have constant values.
|
||||
* @return Map from Variable to the Constant value
|
||||
*/
|
||||
private Map<VariableRef, Constant> findConstantVariables() {
|
||||
final Map<VariableRef, Constant> constants = new LinkedHashMap<>();
|
||||
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitAssignment(StatementAssignment assignment) {
|
||||
if (assignment.getlValue() instanceof VariableRef ) {
|
||||
VariableRef variable = (VariableRef) assignment.getlValue();
|
||||
if (assignment.getrValue1() == null && assignment.getrValue2() instanceof Constant) {
|
||||
if (assignment.getOperator() == null) {
|
||||
// Constant assignment
|
||||
Constant constant = (Constant) assignment.getrValue2();
|
||||
constants.put(variable, constant);
|
||||
} else {
|
||||
// Constant unary expression
|
||||
Constant constant = calculateUnary(assignment.getOperator(), (Constant) assignment.getrValue2());
|
||||
if(constant!=null) {
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
}
|
||||
} else if (assignment.getrValue1() instanceof Constant && assignment.getrValue2() instanceof Constant) {
|
||||
// Constant binary expression
|
||||
Constant constant = calculateBinary(
|
||||
assignment.getOperator(),
|
||||
(Constant) assignment.getrValue1(),
|
||||
(Constant) assignment.getrValue2());
|
||||
if(constant!=null) {
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitPhiBlock(StatementPhiBlock phi) {
|
||||
for (StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
|
||||
if(phiVariable.getValues().size()==1) {
|
||||
StatementPhiBlock.PhiRValue phiRValue = phiVariable.getValues().get(0);
|
||||
if (phiRValue.getrValue() instanceof Constant) {
|
||||
VariableRef variable = phiVariable.getVariable();
|
||||
Constant constant = (Constant) phiRValue.getrValue();
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
visitor.visitGraph(getGraph());
|
||||
return constants;
|
||||
}
|
||||
|
||||
|
||||
public static Constant calculateBinary(Operator operator, Constant c1, Constant c2) {
|
||||
switch (operator.getOperator()) {
|
||||
case "-": {
|
||||
if (c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
|
||||
return new ConstantInteger(getInteger(c1) - getInteger(c2));
|
||||
} else {
|
||||
return new ConstantDouble(getDouble(c1) - getDouble(c2));
|
||||
}
|
||||
}
|
||||
case "+": {
|
||||
if (c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
|
||||
return new ConstantInteger(getInteger(c1) + getInteger(c2));
|
||||
} else {
|
||||
return new ConstantDouble(getDouble(c1) + getDouble(c2));
|
||||
}
|
||||
}
|
||||
case "*": {
|
||||
if (c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
|
||||
return new ConstantInteger(getInteger(c1) * getInteger(c2));
|
||||
} else {
|
||||
return new ConstantDouble(getDouble(c1) * getDouble(c2));
|
||||
}
|
||||
}
|
||||
case "/": {
|
||||
if (c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) {
|
||||
return new ConstantInteger(getInteger(c1) / getInteger(c2));
|
||||
} else {
|
||||
return new ConstantDouble(getDouble(c1) / getDouble(c2));
|
||||
}
|
||||
}
|
||||
case "*idx": {
|
||||
// Cannot be directly propagated
|
||||
return null;
|
||||
}
|
||||
default:
|
||||
throw new RuntimeException("Unhandled Binary Operator " + operator.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer getInteger(Constant constant) {
|
||||
if (constant instanceof ConstantInteger) {
|
||||
return ((ConstantInteger) constant).getNumber();
|
||||
} else {
|
||||
throw new RuntimeException("Type Mismatch. Constant is not an integer number " + constant);
|
||||
}
|
||||
}
|
||||
|
||||
private static Double getDouble(Constant constant) {
|
||||
if (constant instanceof ConstantDouble) {
|
||||
return ((ConstantDouble) constant).getNumber();
|
||||
} else if (constant instanceof ConstantInteger) {
|
||||
return ((ConstantInteger) constant).getNumber().doubleValue();
|
||||
} else {
|
||||
throw new RuntimeException("Type Mismatch. Constant is not a number " + constant);
|
||||
}
|
||||
}
|
||||
|
||||
public static Constant calculateUnary(Operator operator, Constant c) {
|
||||
switch (operator.getOperator()) {
|
||||
case "-": {
|
||||
if (c instanceof ConstantInteger) {
|
||||
ConstantInteger cInt = (ConstantInteger) c;
|
||||
return new ConstantInteger(-cInt.getNumber());
|
||||
} else if (c instanceof ConstantDouble) {
|
||||
ConstantDouble cDoub = (ConstantDouble) c;
|
||||
return new ConstantDouble(-cDoub.getNumber());
|
||||
} else {
|
||||
throw new RuntimeException("Type mismatch. Unary Minus cannot handle value " + c);
|
||||
}
|
||||
}
|
||||
case "+": {
|
||||
return c;
|
||||
}
|
||||
case "++": {
|
||||
ConstantInteger cInt = (ConstantInteger) c;
|
||||
return new ConstantInteger(cInt.getNumber()+1);
|
||||
}
|
||||
case "--": {
|
||||
ConstantInteger cInt = (ConstantInteger) c;
|
||||
return new ConstantInteger(cInt.getNumber()-1);
|
||||
}
|
||||
case "*": { // pointer dereference
|
||||
return null;
|
||||
}
|
||||
default:
|
||||
throw new RuntimeException("Unhandled Unary Operator " + operator.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -84,6 +84,7 @@ public class Pass3VariableRegisterWeightAnalysis extends Pass2Base {
|
||||
}
|
||||
|
||||
private double addWeight(VariableRef variable, LabelRef block) {
|
||||
Variable var = getProgram().getScope().getVariable(variable);
|
||||
int depth = loopSet.getMaxLoopDepth(block);
|
||||
double w = 1.0 + Math.pow(10.0, depth);
|
||||
LiveRange liveRange = liveRangeVariables.getLiveRange(variable);
|
||||
|
@ -67,7 +67,8 @@ public class Pass4AssertNoCpuClobber extends Pass2Base {
|
||||
List<VariableRef> aliveVars = new ArrayList<>(getProgram().getLiveRangeVariables().getAliveEffective(statement));
|
||||
// Non-assigned alive variables must not be clobbered
|
||||
for (VariableRef aliveVar : aliveVars) {
|
||||
Registers.Register aliveVarRegister = getProgram().getScope().getVariable(aliveVar).getAllocation();
|
||||
Variable variable = getProgram().getScope().getVariable(aliveVar);
|
||||
Registers.Register aliveVarRegister = variable.getAllocation();
|
||||
if (aliveVarRegister.isZp()) {
|
||||
// No need to check a zp-register - here we are only interested in CPU registers
|
||||
continue;
|
||||
|
@ -24,6 +24,10 @@ public class TestCompilationOutput extends TestCase {
|
||||
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
|
||||
}
|
||||
|
||||
public void testConstantMin() throws IOException, URISyntaxException {
|
||||
compileAndCompare("constantmin");
|
||||
}
|
||||
|
||||
public void testLiveRange() throws IOException, URISyntaxException {
|
||||
compileAndCompare("liverange");
|
||||
}
|
||||
|
16
src/main/java/dk/camelot64/kickc/test/constantmin.kc
Normal file
16
src/main/java/dk/camelot64/kickc/test/constantmin.kc
Normal file
@ -0,0 +1,16 @@
|
||||
const byte* SCREEN = $0400;
|
||||
const byte STAR = 81;
|
||||
|
||||
byte* VIC = $d000;
|
||||
byte* BGCOL = VIC+$21;
|
||||
byte RED = 2;
|
||||
|
||||
main();
|
||||
|
||||
void main() {
|
||||
*SCREEN = STAR;
|
||||
*BGCOL = RED;
|
||||
for(byte i: 40..79) {
|
||||
SCREEN[i] = (STAR+1);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user