1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 17:54:40 +00:00

Implemented true recursive variable replacer that can replace into pointers/value lists. Also using this when building SSA. Prepared syntax ant type inference for building a word from 2 bytes using word w = { b1, b2 };

This commit is contained in:
Jesper Gravgaard 2017-12-25 20:19:53 +01:00
parent eb6ee9bff8
commit e314794f0b
19 changed files with 2401 additions and 269 deletions

View File

@ -27,7 +27,7 @@ public class ConstantInteger implements ConstantValue {
}
public SymbolType getType() {
ArrayList<SymbolTypeInteger> potentialTypes = new ArrayList<>();
ArrayList<SymbolType> potentialTypes = new ArrayList<>();
Integer number = getNumber();
for (SymbolTypeInteger typeInteger : SymbolType.getIntegerTypes()) {
if(number>=typeInteger.getMinValue() && number<= typeInteger.getMaxValue()) {

View File

@ -5,4 +5,7 @@ public interface PointerDereference extends LValue {
RValue getPointer();
void setPointer(RValue pointer);
}

View File

@ -32,7 +32,12 @@ public class SymbolTypeArray extends SymbolTypePointer {
@Override
public String getTypeName() {
return getElementType().getTypeName()+"["+(size==null?"":size)+"]";
SymbolType elementType = getElementType();
if(elementType instanceof SymbolTypeInline) {
return "("+elementType.getTypeName()+")"+"["+(size==null?"":size)+"]";
}else {
return elementType.getTypeName()+"["+(size==null?"":size)+"]";
}
}
@Override

View File

@ -1,5 +1,6 @@
package dk.camelot64.kickc.model;
import java.util.ArrayList;
import java.util.Collection;
/**
@ -40,7 +41,11 @@ public class SymbolTypeInference {
public static SymbolType inferType(ProgramScope programScope, RValue rValue1, Operator operator, RValue rValue2) {
if (rValue1 instanceof ConstantValue && rValue2 instanceof ConstantValue) {
ConstantValue value = ConstantValueCalculator.calcValue(programScope, (ConstantValue) rValue1, operator, (ConstantValue) rValue2);
ConstantValue value = ConstantValueCalculator.calcValue(
programScope,
(ConstantValue) rValue1,
operator,
(ConstantValue) rValue2);
if (value != null) {
return value.getType(programScope);
}
@ -66,7 +71,7 @@ public class SymbolTypeInference {
return SymbolType.BYTE;
}
} else if (Operator.HIBYTE.equals(operator)) {
if (subType instanceof SymbolTypePointer || SymbolType.WORD.equals(subType) || SymbolType.SWORD.equals(subType) ) {
if (subType instanceof SymbolTypePointer || SymbolType.WORD.equals(subType) || SymbolType.SWORD.equals(subType)) {
return SymbolType.BYTE;
}
} else if (Operator.CAST_BYTE.equals(operator)) {
@ -89,9 +94,9 @@ public class SymbolTypeInference {
return inferPlus(type1, type2);
} else if (Operator.MINUS.equals(operator)) {
return inferMinus(type1, type2);
} else if(Operator.SET_HIBYTE.equals(operator)) {
} else if (Operator.SET_HIBYTE.equals(operator)) {
return type1;
} else if(Operator.SET_LOWBYTE.equals(operator)) {
} else if (Operator.SET_LOWBYTE.equals(operator)) {
return type1;
}
@ -209,14 +214,15 @@ public class SymbolTypeInference {
private static boolean isInteger(SymbolType type) {
if (SymbolType.BYTE.equals(type)) {
return true;
} else if(SymbolType.WORD.equals(type)) {
} else if (SymbolType.WORD.equals(type)) {
return true;
} else if(SymbolType.SBYTE.equals(type)) {
} else if (SymbolType.SBYTE.equals(type)) {
return true;
} else if(SymbolType.SWORD.equals(type)) {
return true;
} else if(type instanceof SymbolTypeInline) {
} else if (SymbolType.SWORD.equals(type)) {
return true;
} else if (type instanceof SymbolTypeInline) {
SymbolTypeInline typeInline = (SymbolTypeInline) type;
return typeInline.isByte() || typeInline.isSByte() || typeInline.isWord() || typeInline.isSWord();
} else {
return false;
}
@ -248,8 +254,8 @@ public class SymbolTypeInference {
} else if (rValue instanceof ConstantBinary) {
ConstantBinary constBin = (ConstantBinary) rValue;
return inferType(symbols, constBin.getLeft(), constBin.getOperator(), constBin.getRight());
} else if (rValue instanceof ValueArray) {
type = inferTypeArray(symbols, (ValueArray)rValue);
} else if (rValue instanceof ValueList) {
type = inferTypeList(symbols, (ValueList) rValue);
} else if (rValue instanceof PointerDereference) {
SymbolType pointerType = inferType(symbols, ((PointerDereference) rValue).getPointer());
if (pointerType instanceof SymbolTypePointer) {
@ -264,16 +270,16 @@ public class SymbolTypeInference {
return type;
}
private static SymbolType inferTypeArray(ProgramScope symbols, ValueArray array) {
private static SymbolType inferTypeList(ProgramScope symbols, ValueList list) {
SymbolType elmType = null;
for (RValue elm : array.getList()) {
for (RValue elm : list.getList()) {
SymbolType type = inferType(symbols, elm);
if(elmType==null) {
if (elmType == null) {
elmType = type;
} else {
// element type already defined - check for a match
if(!typeMatch(elmType, type)) {
if(typeMatch(type, elmType)) {
if (!typeMatch(elmType, type)) {
if (typeMatch(type, elmType)) {
elmType = type;
} else {
throw new RuntimeException("Array element has type mismatch " + elm.toString() + " not matching type " + elmType.getTypeName());
@ -281,10 +287,18 @@ public class SymbolTypeInference {
}
}
}
if(elmType!=null) {
return new SymbolTypeArray(elmType);
if (elmType != null) {
if ((list.getList().size() == 2 && SymbolType.isByte(elmType) || SymbolType.isSByte(elmType))) {
// Potentially a word constructor - return a composite type
ArrayList<SymbolType> types = new ArrayList<>();
types.add(new SymbolTypeArray(elmType));
types.add(SymbolType.WORD);
return new SymbolTypeInline(types);
} else {
return new SymbolTypeArray(elmType);
}
} else {
throw new RuntimeException("Cannot infer array element type "+array.toString());
throw new RuntimeException("Cannot infer list element type " + list.toString());
}
}
@ -314,24 +328,49 @@ public class SymbolTypeInference {
// Types match directly
return true;
} else if (rValueType instanceof SymbolTypeInline) {
if(lValueType instanceof SymbolTypeInline) {
Collection<SymbolType> rTypes = ((SymbolTypeInline) rValueType).getTypes();
if (lValueType instanceof SymbolTypeInline) {
// Both are inline types - RValue type must be superset of LValue
Collection<SymbolTypeInteger> lValueTypes = ((SymbolTypeInline) lValueType).getTypes();
Collection<SymbolTypeInteger> rValueTypes = ((SymbolTypeInline) rValueType).getTypes();
if(rValueTypes.containsAll(lValueTypes)) {
return true;
}
} else if (((SymbolTypeInline) rValueType).getTypes().contains(lValueType)) {
// Types match because the right side is a constant that matches the left side
return true;
Collection<SymbolType> lTypes = ((SymbolTypeInline) lValueType).getTypes();
return typeContainsMatchAll(lTypes, rTypes);
} else {
// Types match because the right side matches the left side
return typeContainsMatch(lValueType, rTypes);
}
} else if (lValueType instanceof SymbolTypePointer && rValueType instanceof SymbolTypePointer) {
return typeMatch(((SymbolTypePointer) lValueType).getElementType(), ((SymbolTypePointer) rValueType).getElementType());
return typeMatch(
((SymbolTypePointer) lValueType).getElementType(),
((SymbolTypePointer) rValueType).getElementType());
} else if (SymbolType.STRING.equals(rValueType)) {
if(lValueType instanceof SymbolTypePointer && SymbolType.isByte(((SymbolTypePointer) lValueType).getElementType())) {
if (lValueType instanceof SymbolTypePointer && SymbolType.isByte(((SymbolTypePointer) lValueType).getElementType())) {
return true;
}
}
return false;
}
private static boolean typeContainsMatchAll(Collection<SymbolType> lTypes, Collection<SymbolType> rTypes) {
for (SymbolType lType : lTypes) {
if (!typeContainsMatch(lType, rTypes)) {
return false;
}
}
return true;
}
/**
* Determine is a list of potential inferred types contains a match for another type
* @param lValueType The type (rValue) we want to find a match for in the list
* @param rTypes The list of inferred potential types
* @return true if the list has a match
*/
private static boolean typeContainsMatch(SymbolType lValueType, Collection<SymbolType> rTypes) {
for (SymbolType rType : rTypes) {
if (typeMatch(lValueType, rType)) {
return true;
}
}
return false;
}
}

View File

@ -3,21 +3,21 @@ package dk.camelot64.kickc.model;
import java.util.Collection;
/**
* Symbol Type of an inline numeric expression. Inline expressions can match multiple types depending on the actual value,
* eg. the value 27 matches both byte and signed byte (which can in turn be promoted to word/signed word) , while the value -252 only matches signed word.
* Symbol Type of an inline expression. Inline expressions can match multiple types depending on the actual value,
* eg. the value 27 matches both byte and signed byte (which can in turn be promoted to word/signed word), while the value -252 only matches signed word.
*/
public class SymbolTypeInline implements SymbolType {
/**
* All potential types for the inline constant.
*/
private Collection<SymbolTypeInteger> types;
private Collection<SymbolType> types;
public SymbolTypeInline(Collection<SymbolTypeInteger> types) {
public SymbolTypeInline(Collection<SymbolType> types) {
this.types = types;
}
public Collection<SymbolTypeInteger> getTypes() {
public Collection<SymbolType> getTypes() {
return types;
}
@ -25,10 +25,10 @@ public class SymbolTypeInline implements SymbolType {
public String getTypeName() {
StringBuilder name = new StringBuilder();
boolean first = true;
for (SymbolTypeInteger type : types) {
if(first) {
for (SymbolType type : types) {
if (first) {
first = false;
} else {
} else {
name.append("/");
}
name.append(type);
@ -38,8 +38,12 @@ public class SymbolTypeInline implements SymbolType {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SymbolTypeInline that = (SymbolTypeInline) o;
return types != null ? types.equals(that.types) : that.types == null;
}
@ -62,15 +66,28 @@ public class SymbolTypeInline implements SymbolType {
return types.contains(BYTE);
}
/**
* Is signed byte one of the potential types
* @return true if signed byte is a potential type
*/
public boolean isSByte() {
return types.contains(SBYTE);
}
/**
* Is unsigned word one of the potential types
* @return true if unsigned word is a potential type
*/
public boolean isWord() {
return types.contains(WORD);
}
/**
* Is signed word one of the potential types
* @return true if signed word is a potential type
*/
public boolean isSWord() {
return types.contains(SWORD);
}
}

View File

@ -2,12 +2,15 @@ package dk.camelot64.kickc.model;
import java.util.List;
/** An array of sub-values. Only used for variable initializers. Compilation execution will typically resolve it into a constant array before ASM-generation. */
public class ValueArray implements RValue {
/** A list of sub-values. Used for array variable initializers and word from byte constructors
* (in the future also usable for dword from byte, dword from double etc.).
* Compilation execution will resolve into a constant array,
* constant word or word constructor operator before ASM-generation. */
public class ValueList implements RValue {
private List<RValue> list;
public ValueArray(List<RValue> list) {
public ValueList(List<RValue> list) {
this.list = list;
}

View File

@ -64,6 +64,27 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
}
}
/**
* Version all variable uses in the replacable value
*
* @param replacableValue The value to version variable usages in
* @param blockVersions Newest version of variables in the block.
* @param blockNewPhis New phi functions introduced in the block to create versions of variables.
*/
private void execute(
VariableReplacer.ReplacableValue replacableValue,
Map<VariableUnversioned, VariableVersion> blockVersions,
Map<VariableUnversioned, VariableVersion> blockNewPhis) {
RValue value = replacableValue.get();
VariableVersion version = findOrCreateVersion(value, blockVersions, blockNewPhis);
if (version != null) {
replacableValue.set(version.getRef());
}
for (VariableReplacer.ReplacableValue subValue : replacableValue.getSubValues()) {
execute(subValue, blockVersions, blockNewPhis);
}
}
/**
* Version all uses of non-versioned non-intermediary variables
*/
@ -75,49 +96,13 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
Map<VariableUnversioned, VariableVersion> blockNewPhis = new LinkedHashMap<>();
for (Statement statement : block.getStatements()) {
if (statement instanceof StatementReturn) {
StatementReturn statementReturn = (StatementReturn) statement;
if (statementReturn.getValue() instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) ((StatementReturn) statement).getValue();
RValue pointer = deref.getPointer();
VariableVersion version = findOrCreateVersion(pointer, blockVersions, blockNewPhis);
if (version != null) {
deref.setPointer(version.getRef());
}
} else {
VariableVersion version = findOrCreateVersion(statementReturn.getValue(), blockVersions, blockNewPhis);
if (version != null) {
statementReturn.setValue(version.getRef());
}
}
}
if (statement instanceof StatementAssignment) {
execute(new VariableReplacer.ReplacableReturn((StatementReturn) statement), blockVersions, blockNewPhis);
} else if (statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
if (assignment.getrValue1() instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) ((StatementAssignment) statement).getrValue1();
RValue pointer = deref.getPointer();
VariableVersion version = findOrCreateVersion(pointer, blockVersions, blockNewPhis);
if (version != null) {
deref.setPointer(version.getRef());
}
} else {
VariableVersion version = findOrCreateVersion(assignment.getrValue1(), blockVersions, blockNewPhis);
if (version != null) {
assignment.setrValue1(version.getRef());
}
}
if (assignment.getrValue2() instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) ((StatementAssignment) statement).getrValue2();
RValue pointer = deref.getPointer();
VariableVersion version = findOrCreateVersion(pointer, blockVersions, blockNewPhis);
if (version != null) {
deref.setPointer(version.getRef());
}
} else {
VariableVersion version = findOrCreateVersion(assignment.getrValue2(), blockVersions, blockNewPhis);
if (version != null) {
assignment.setrValue2(version.getRef());
}
}
execute(new VariableReplacer.ReplacableRValue1(assignment), blockVersions, blockNewPhis);
execute(new VariableReplacer.ReplacableRValue2(assignment), blockVersions, blockNewPhis);
execute(new VariableReplacer.ReplacableLValue(assignment), blockVersions, blockNewPhis);
// Update map of versions encountered in the block
LValue lValue = assignment.getlValue();
if (lValue instanceof VariableRef) {
@ -127,25 +112,6 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
VariableVersion versioned = (VariableVersion) variable;
blockVersions.put(versioned.getVersionOf(), versioned);
}
} else if (lValue instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) lValue;
RValue pointer = deref.getPointer();
VariableVersion version = findOrCreateVersion(pointer, blockVersions, blockNewPhis);
if (version != null) {
deref.setPointer(version.getRef());
}
} else if (lValue instanceof PointerDereferenceIndexed) {
PointerDereferenceIndexed deref = (PointerDereferenceIndexed) lValue;
RValue pointer = deref.getPointer();
VariableVersion version = findOrCreateVersion(pointer, blockVersions, blockNewPhis);
if (version != null) {
deref.setPointer(version.getRef());
}
RValue index = deref.getIndex();
VariableVersion iVersion = findOrCreateVersion(index, blockVersions, blockNewPhis);
if (iVersion != null) {
deref.setIndex(iVersion.getRef());
}
}
}
}

View File

@ -80,9 +80,9 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
if (constant != null) {
constants.put(variable, constant);
}
} else if (assignment.getrValue2() instanceof ValueArray && assignment.getOperator() == null && assignment.getrValue1() == null) {
ValueArray valueArray = (ValueArray) assignment.getrValue2();
List<RValue> values = valueArray.getList();
} else if (assignment.getrValue2() instanceof ValueList && assignment.getOperator() == null && assignment.getrValue1() == null) {
ValueList valueList = (ValueList) assignment.getrValue2();
List<RValue> values = valueList.getList();
boolean allConstant = true;
SymbolType elementType = null;
List<ConstantValue> elements = new ArrayList<>();
@ -94,7 +94,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
elementType = type;
} else {
if (!SymbolTypeInference.typeMatch(type, elementType)) {
throw new RuntimeException("Array type mismatch " + elementType + " does not match " + type + " " + valueArray.toString(getProgram()));
throw new RuntimeException("Array type mismatch " + elementType + " does not match " + type + " " + valueList.toString(getProgram()));
}
}
elements.add(constantValue);

View File

@ -48,7 +48,7 @@ public abstract class Pass2SsaOptimization {
*/
public void replaceVariables(final Map<? extends SymbolRef, ? extends RValue> aliases) {
VariableReplacer replacer = new VariableReplacer(aliases);
replacer.getReplacement(getGraph());
replacer.execute(getGraph());
}
/**

View File

@ -213,9 +213,9 @@ public class Pass3VariableReferenceInfos extends Pass2Base {
return used;
} else if (rValue instanceof VariableRef) {
return Arrays.asList((VariableRef) rValue);
} else if (rValue instanceof ValueArray) {
} else if (rValue instanceof ValueList) {
LinkedHashSet<VariableRef> used = new LinkedHashSet<>();
for (RValue value : ((ValueArray) rValue).getList()) {
for (RValue value : ((ValueList) rValue).getList()) {
used.addAll(getReferenced(value));
}
return used;

View File

@ -455,7 +455,7 @@ public class StatementSequenceGenerator extends KickCBaseVisitor<Object> {
RValue rValue = (RValue) visit(initializer);
initValues.add(rValue);
}
return new ValueArray(initValues);
return new ValueList(initValues);
}
@Override

View File

@ -2,10 +2,7 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* A replacer capable to alias all usages of a variable (or constant var) with a suitable replacement
@ -18,9 +15,55 @@ public class VariableReplacer {
this.aliases = aliases;
}
public void getReplacement(ControlFlowGraph graph) {
ControlFlowGraphBaseVisitor<Void> visitor = new GraphReplacer();
visitor.visitGraph(graph);
public void execute(ControlFlowGraph graph) {
//new GraphReplacer().visitGraph(graph);
for (ControlFlowBlock block : graph.getAllBlocks()) {
for (Statement statement : block.getStatements()) {
if (statement instanceof StatementAssignment) {
execute(new ReplacableLValue((StatementLValue) statement));
execute(new ReplacableRValue1((StatementAssignment) statement));
execute(new ReplacableRValue2((StatementAssignment) statement));
} else if (statement instanceof StatementCall) {
execute(new ReplacableLValue((StatementLValue) statement));
StatementCall call = (StatementCall) statement;
if(call.getParameters()!=null) {
int size = call.getParameters().size();
for (int i = 0; i < size; i++) {
execute(new ReplacableCallParameter(call, i));
}
}
} else if (statement instanceof StatementConditionalJump) {
execute(new ReplacableCondRValue1((StatementConditionalJump) statement));
execute(new ReplacableCondRValue2((StatementConditionalJump) statement));
} else if (statement instanceof StatementReturn) {
execute(new ReplacableReturn((StatementReturn) statement));
} else if (statement instanceof StatementPhiBlock) {
for (StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) {
execute(new ReplacablePhiVariable(phiVariable));
int size = phiVariable.getValues().size();
for (int i = 0; i < size; i++) {
execute(new ReplacablePhiValue(phiVariable, i));
}
}
}
}
}
}
/**
* Execute replacements inside a replacable value - and its sub-values.
* @param replacable The replacable value
*/
void execute(ReplacableValue replacable) {
if(replacable.get()!=null) {
RValue replacement = getReplacement(replacable.get());
if(replacement!=null) {
replacable.set(replacement);
}
for (ReplacableValue subReplacable : replacable.getSubValues()) {
execute(subReplacable);
}
}
}
/**
@ -32,14 +75,14 @@ public class VariableReplacer {
* @return The alias to use. Null if no alias exists.
*/
public RValue getReplacement(RValue rValue) {
if(rValue instanceof SymbolRef) {
if (rValue instanceof SymbolRef) {
RValue alias = aliases.get(rValue);
if(alias!=null) {
if(alias.equals(rValue)) {
if (alias != null) {
if (alias.equals(rValue)) {
return alias;
}
RValue replacement = getReplacement(alias);
if(replacement!=null) {
if (replacement != null) {
return replacement;
} else {
return alias;
@ -72,166 +115,264 @@ public class VariableReplacer {
}
/**
* Visitor capable of handling replacements in an entire flow graph.
* Interface representing an RValue that can be replaced.
* The value may have sub-values that can also be replaced.
*/
private class GraphReplacer extends ControlFlowGraphBaseVisitor<Void> {
public static abstract class ReplacableValue {
@Override
public Void visitAssignment(StatementAssignment assignment) {
LValue lValue = assignment.getlValue();
if (getReplacement(lValue) != null) {
RValue alias = getReplacement(lValue);
if (alias instanceof LValue) {
assignment.setlValue((LValue) alias);
} else {
throw new RuntimeException("Error replacing LValue variable " + lValue + " with " + alias);
}
}
if (getReplacement(assignment.getrValue1()) != null) {
assignment.setrValue1(getReplacement(assignment.getrValue1()));
} else {
if(assignment.getrValue1() instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) assignment.getrValue1();
RValue pointer = deref.getPointer();
if (getReplacement(pointer) != null) {
deref.setPointer(getReplacement(pointer));
}
}
}
if (getReplacement(assignment.getrValue2()) != null) {
assignment.setrValue2(getReplacement(assignment.getrValue2()));
} else {
if(assignment.getrValue2() instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) assignment.getrValue2();
RValue pointer = deref.getPointer();
if (getReplacement(pointer) != null) {
deref.setPointer(getReplacement(pointer));
}
}
}
// Handle pointer dereference in LValue
if (lValue instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) lValue;
RValue pointer = deref.getPointer();
if (getReplacement(pointer) != null) {
deref.setPointer(getReplacement(pointer));
}
} else if (lValue instanceof PointerDereferenceIndexed) {
PointerDereferenceIndexed deref = (PointerDereferenceIndexed) lValue;
RValue pointer = deref.getPointer();
if (getReplacement(pointer) != null) {
deref.setPointer(getReplacement(pointer));
}
RValue index = deref.getIndex();
if (getReplacement(index) != null) {
deref.setIndex(getReplacement(index));
}
}
// Handle pointer dereference in RValue
public abstract RValue get();
return null;
public abstract void set(RValue value);
public Collection<ReplacableValue> getSubValues() {
RValue value = get();
ArrayList<ReplacableValue> subValues = new ArrayList<>();
if (value instanceof PointerDereferenceIndexed) {
subValues.add(new ReplacablePointer((PointerDereference) value));
subValues.add(new ReplacablePointerIndex((PointerDereferenceIndexed) value));
} else if (value instanceof PointerDereferenceSimple) {
subValues.add(new ReplacablePointer((PointerDereference) value));
} else if (value instanceof ValueList) {
ValueList valueList = (ValueList) value;
int size = valueList.getList().size();
for (int i = 0; i < size; i++) {
subValues.add(new ReplacableListElement(valueList, i));
}
}
return subValues;
}
}
/** Replacable LValue as part of an assignment statement (or a call). */
public static class ReplacableLValue extends ReplacableValue {
private final StatementLValue statement;
public ReplacableLValue(StatementLValue statement) {
this.statement = statement;
}
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
if (getReplacement(conditionalJump.getrValue1()) != null) {
conditionalJump.setrValue1(getReplacement(conditionalJump.getrValue1()));
} else {
if (conditionalJump.getrValue1() instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) conditionalJump.getrValue1();
RValue pointer = deref.getPointer();
if (getReplacement(pointer) != null) {
deref.setPointer(getReplacement(pointer));
}
}
}
if (getReplacement(conditionalJump.getrValue2()) != null) {
conditionalJump.setrValue2(getReplacement(conditionalJump.getrValue2()));
} else {
if (conditionalJump.getrValue2() instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) conditionalJump.getrValue2();
RValue pointer = deref.getPointer();
if (getReplacement(pointer) != null) {
deref.setPointer(getReplacement(pointer));
}
}
}
return null;
public RValue get() {
return statement.getlValue();
}
@Override
public Void visitReturn(StatementReturn aReturn) {
if (getReplacement(aReturn.getValue()) != null) {
aReturn.setValue(getReplacement(aReturn.getValue()));
} else {
if (aReturn.getValue() instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) aReturn.getValue();
RValue pointer = deref.getPointer();
if (getReplacement(pointer) != null) {
deref.setPointer(getReplacement(pointer));
}
}
}
return null;
public void set(RValue value) {
statement.setlValue((LValue) value);
}
}
/** Replacable pointer inside a pointer dererence value. */
public static class ReplacablePointer extends ReplacableValue {
private final PointerDereference pointer;
ReplacablePointer(PointerDereference pointer) {
this.pointer = pointer;
}
@Override
public Void visitCall(StatementCall call) {
if (call.getParameters() != null) {
List<RValue> newParams = new ArrayList<>();
for (RValue parameter : call.getParameters()) {
RValue newParam = parameter;
if (getReplacement(parameter) != null) {
newParam = getReplacement(parameter);
} else {
if (parameter instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) parameter;
RValue pointer = deref.getPointer();
if (getReplacement(pointer) != null) {
deref.setPointer(getReplacement(pointer));
}
}
}
newParams.add(newParam);
}
call.setParameters(newParams);
}
return null;
public RValue get() {
return pointer.getPointer();
}
@Override
public Void visitPhiBlock(StatementPhiBlock phi) {
for (StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
if (getReplacement(phiVariable.getVariable()) != null) {
RValue alias = getReplacement(phiVariable.getVariable());
if (alias instanceof LValue) {
phiVariable.setVariable((VariableRef) alias);
}
}
List<StatementPhiBlock.PhiRValue> phirValues = phiVariable.getValues();
Iterator<StatementPhiBlock.PhiRValue> it = phirValues.iterator();
while (it.hasNext()) {
StatementPhiBlock.PhiRValue phirValue = it.next();
if (getReplacement(phirValue.getrValue()) != null) {
RValue alias = getReplacement(phirValue.getrValue());
if (LValue.VOID.equals(alias)) {
it.remove();
} else {
phirValue.setrValue(alias);
}
} else {
if(phirValue.getrValue() instanceof PointerDereferenceSimple) {
PointerDereferenceSimple deref = (PointerDereferenceSimple) phirValue.getrValue();
RValue pointer = deref.getPointer();
if (getReplacement(pointer) != null) {
deref.setPointer(getReplacement(pointer));
}
}
}
}
}
return null;
public void set(RValue val) {
pointer.setPointer(val);
}
}
public static class ReplacableListElement extends ReplacableValue {
private ValueList list;
private int idx;
public ReplacableListElement(ValueList list, int idx) {
this.list = list;
this.idx = idx;
}
@Override
public RValue get() {
return list.getList().get(idx);
}
@Override
public void set(RValue value) {
list.getList().set(idx, value);
}
}
/** Replacable pointer index inside a indexed pointer dererence value. */
public static class ReplacablePointerIndex extends ReplacableValue {
private final PointerDereferenceIndexed pointer;
ReplacablePointerIndex(PointerDereferenceIndexed pointer) {
this.pointer = pointer;
}
@Override
public RValue get() {
return pointer.getIndex();
}
@Override
public void set(RValue val) {
pointer.setIndex(val);
}
}
public static class ReplacableRValue1 extends ReplacableValue {
private final StatementAssignment statement;
public ReplacableRValue1(StatementAssignment statement) {
this.statement = statement;
}
@Override
public RValue get() {
return statement.getrValue1();
}
@Override
public void set(RValue value) {
statement.setrValue1(value);
}
}
public static class ReplacableRValue2 extends ReplacableValue {
private final StatementAssignment statement;
public ReplacableRValue2(StatementAssignment statement) {
this.statement = statement;
}
@Override
public RValue get() {
return statement.getrValue2();
}
@Override
public void set(RValue value) {
statement.setrValue2(value);
}
}
public static class ReplacableCallParameter extends ReplacableValue {
private final StatementCall call;
private final int i;
public ReplacableCallParameter(StatementCall call, int i) {
this.call = call;
this.i = i;
}
@Override
public RValue get() {
return call.getParameters().get(i);
}
@Override
public void set(RValue value) {
call.getParameters().set(i, value);
}
}
public static class ReplacableCondRValue1 extends ReplacableValue {
private final StatementConditionalJump statement;
public ReplacableCondRValue1(StatementConditionalJump statement) {
this.statement = statement;
}
@Override
public RValue get() {
return statement.getrValue1();
}
@Override
public void set(RValue value) {
statement.setrValue1(value);
}
}
public static class ReplacableCondRValue2 extends ReplacableValue {
private final StatementConditionalJump statement;
public ReplacableCondRValue2(StatementConditionalJump statement) {
this.statement = statement;
}
@Override
public RValue get() {
return statement.getrValue2();
}
@Override
public void set(RValue value) {
statement.setrValue2(value);
}
}
public static class ReplacableReturn extends ReplacableValue {
private final StatementReturn statement;
public ReplacableReturn(StatementReturn statement) {
this.statement = statement;
}
@Override
public RValue get() {
return statement.getValue();
}
@Override
public void set(RValue value) {
statement.setValue(value);
}
}
public static class ReplacablePhiValue extends ReplacableValue {
private final StatementPhiBlock.PhiVariable phiVariable;
private final int i;
public ReplacablePhiValue(StatementPhiBlock.PhiVariable phiVariable, int i) {
this.phiVariable = phiVariable;
this.i = i;
}
@Override
public RValue get() {
return phiVariable.getValues().get(i).getrValue();
}
@Override
public void set(RValue value) {
phiVariable.getValues().get(i).setrValue(value);
}
}
/** Replacable LValue as part of an assignment statement (or a call). */
public static class ReplacablePhiVariable extends ReplacableValue {
private final StatementPhiBlock.PhiVariable phiVariable;
public ReplacablePhiVariable(StatementPhiBlock.PhiVariable phiVariable) {
this.phiVariable = phiVariable;
}
@Override
public RValue get() {
return phiVariable.getVariable();
}
@Override
public void set(RValue value) {
phiVariable.setVariable((VariableRef) value);
}
}
}

View File

@ -22,6 +22,10 @@ public class TestPrograms extends TestCase {
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
}
public void testInlineWord() throws IOException, URISyntaxException {
compileAndCompare("inline-word");
}
public void testSignedWords() throws IOException, URISyntaxException {
compileAndCompare("signed-words");
}
@ -183,6 +187,10 @@ public class TestPrograms extends TestCase {
compileAndCompare("inmemarray");
}
public void testInMemConstArray() throws IOException, URISyntaxException {
compileAndCompare("inmem-const-array");
}
public void testInMemString() throws IOException, URISyntaxException {
compileAndCompare("inmemstring");
}

View File

@ -0,0 +1,12 @@
const byte* SCREEN = $400;
void main() {
byte[] his = { >SCREEN, >SCREEN+1 };
for( byte h: 0..1) {
for (byte l: 4..7) {
word w = { his[h], l };
byte* sc = (byte*)w;
*sc = '*';
}
}
}

View File

@ -0,0 +1,18 @@
byte WHITE = 1;
byte RED = 2;
byte GREEN = 5;
void main() {
byte[] colseq = { WHITE, RED, GREEN };
byte* screen = $0400;
byte* cols = $d800;
byte j = 0;
for( byte i : 0..39) {
screen[i] = '*';
cols[i] = colseq[j];
if(++j==3) {
j=0;
}
}
}

View File

@ -0,0 +1,28 @@
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const WHITE = 1
.const RED = 2
.const GREEN = 5
jsr main
main: {
.const screen = $400
.const cols = $d800
ldy #0
ldx #0
b1:
lda #'*'
sta screen,x
lda colseq,y
sta cols,x
iny
cpy #3
bne b2
ldy #0
b2:
inx
cpx #$28
bne b1
rts
colseq: .byte WHITE, RED, GREEN
}

View File

@ -0,0 +1,32 @@
@begin: scope:[] from
[0] phi() [ ] ( )
to:@1
@1: scope:[] from @begin
[1] phi() [ ] ( )
[2] call main param-assignment [ ] ( )
to:@end
@end: scope:[] from @1
[3] phi() [ ] ( )
main: scope:[main] from @1
[4] phi() [ ] ( main:2 [ ] )
to:main::@1
main::@1: scope:[main] from main main::@2
[5] (byte) main::j#3 ← phi( main/(byte/signed byte/word/signed word) 0 main::@2/(byte) main::j#4 ) [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] )
[5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@2/(byte) main::i#1 ) [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] )
[6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] )
[7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] )
[8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] )
[9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] )
[10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] )
to:main::@2
main::@2: scope:[main] from main::@1 main::@6
[11] (byte) main::j#4 ← phi( main::@6/(byte) main::j#1 main::@1/(byte/signed byte/word/signed word) 0 ) [ main::i#2 main::j#4 ] ( main:2 [ main::i#2 main::j#4 ] )
[12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] )
[13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] )
to:main::@return
main::@return: scope:[main] from main::@2
[14] return [ ] ( main:2 [ ] )
to:@return
main::@6: scope:[main] from main::@1
[15] phi() [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] )
to:main::@2

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
(label) @1
(label) @begin
(label) @end
(byte) GREEN
(const byte) GREEN#0 GREEN = (byte/signed byte/word/signed word) 5
(byte) RED
(const byte) RED#0 RED = (byte/signed byte/word/signed word) 2
(byte) WHITE
(const byte) WHITE#0 WHITE = (byte/signed byte/word/signed word) 1
(void()) main()
(byte~) main::$0 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@6
(label) main::@return
(byte*) main::cols
(const byte*) main::cols#0 cols = ((byte*))(word) 55296
(byte[]) main::colseq
(const byte[]) main::colseq#0 colseq = { (const byte) WHITE#0, (const byte) RED#0, (const byte) GREEN#0 }
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 5.5
(byte) main::j
(byte) main::j#1 reg byte y 11.0
(byte) main::j#3 reg byte y 8.25
(byte) main::j#4 reg byte y 7.333333333333333
(byte*) main::screen
(const byte*) main::screen#0 screen = ((byte*))(word/signed word) 1024
reg byte x [ main::i#2 main::i#1 ]
reg byte y [ main::j#3 main::j#4 main::j#1 ]
reg byte a [ main::$0 ]