1
0
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:
Jesper Gravgaard 2017-10-02 21:47:12 +02:00
parent a553cb97c3
commit 6f2dfdbec3
29 changed files with 798 additions and 303 deletions

View File

@ -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));
}

View File

@ -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

View File

@ -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);
}

View File

@ -3,4 +3,6 @@ package dk.camelot64.kickc.icl;
/** SSA form constant value */
public interface Constant extends RValue {
SymbolType getType(ProgramScope scope);
}

View 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);
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View 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);
}
}

View File

@ -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);

View 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);
}
}

View 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 {
}

View 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;
}
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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()) {

View File

@ -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");
}
}

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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());
}
}
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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());
}
}
}

View File

@ -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());
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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");
}

View 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);
}
}