mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-08-14 07:25:46 +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:
@@ -27,7 +27,7 @@ public class ConstantInteger implements ConstantValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SymbolType getType() {
|
public SymbolType getType() {
|
||||||
ArrayList<SymbolTypeInteger> potentialTypes = new ArrayList<>();
|
ArrayList<SymbolType> potentialTypes = new ArrayList<>();
|
||||||
Integer number = getNumber();
|
Integer number = getNumber();
|
||||||
for (SymbolTypeInteger typeInteger : SymbolType.getIntegerTypes()) {
|
for (SymbolTypeInteger typeInteger : SymbolType.getIntegerTypes()) {
|
||||||
if(number>=typeInteger.getMinValue() && number<= typeInteger.getMaxValue()) {
|
if(number>=typeInteger.getMinValue() && number<= typeInteger.getMaxValue()) {
|
||||||
|
@@ -5,4 +5,7 @@ public interface PointerDereference extends LValue {
|
|||||||
|
|
||||||
RValue getPointer();
|
RValue getPointer();
|
||||||
|
|
||||||
|
void setPointer(RValue pointer);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -32,7 +32,12 @@ public class SymbolTypeArray extends SymbolTypePointer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTypeName() {
|
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
|
@Override
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package dk.camelot64.kickc.model;
|
package dk.camelot64.kickc.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,7 +41,11 @@ public class SymbolTypeInference {
|
|||||||
|
|
||||||
public static SymbolType inferType(ProgramScope programScope, RValue rValue1, Operator operator, RValue rValue2) {
|
public static SymbolType inferType(ProgramScope programScope, RValue rValue1, Operator operator, RValue rValue2) {
|
||||||
if (rValue1 instanceof ConstantValue && rValue2 instanceof ConstantValue) {
|
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) {
|
if (value != null) {
|
||||||
return value.getType(programScope);
|
return value.getType(programScope);
|
||||||
}
|
}
|
||||||
@@ -66,7 +71,7 @@ public class SymbolTypeInference {
|
|||||||
return SymbolType.BYTE;
|
return SymbolType.BYTE;
|
||||||
}
|
}
|
||||||
} else if (Operator.HIBYTE.equals(operator)) {
|
} 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;
|
return SymbolType.BYTE;
|
||||||
}
|
}
|
||||||
} else if (Operator.CAST_BYTE.equals(operator)) {
|
} else if (Operator.CAST_BYTE.equals(operator)) {
|
||||||
@@ -89,9 +94,9 @@ public class SymbolTypeInference {
|
|||||||
return inferPlus(type1, type2);
|
return inferPlus(type1, type2);
|
||||||
} else if (Operator.MINUS.equals(operator)) {
|
} else if (Operator.MINUS.equals(operator)) {
|
||||||
return inferMinus(type1, type2);
|
return inferMinus(type1, type2);
|
||||||
} else if(Operator.SET_HIBYTE.equals(operator)) {
|
} else if (Operator.SET_HIBYTE.equals(operator)) {
|
||||||
return type1;
|
return type1;
|
||||||
} else if(Operator.SET_LOWBYTE.equals(operator)) {
|
} else if (Operator.SET_LOWBYTE.equals(operator)) {
|
||||||
return type1;
|
return type1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,14 +214,15 @@ public class SymbolTypeInference {
|
|||||||
private static boolean isInteger(SymbolType type) {
|
private static boolean isInteger(SymbolType type) {
|
||||||
if (SymbolType.BYTE.equals(type)) {
|
if (SymbolType.BYTE.equals(type)) {
|
||||||
return true;
|
return true;
|
||||||
} else if(SymbolType.WORD.equals(type)) {
|
} else if (SymbolType.WORD.equals(type)) {
|
||||||
return true;
|
return true;
|
||||||
} else if(SymbolType.SBYTE.equals(type)) {
|
} else if (SymbolType.SBYTE.equals(type)) {
|
||||||
return true;
|
return true;
|
||||||
} else if(SymbolType.SWORD.equals(type)) {
|
} else if (SymbolType.SWORD.equals(type)) {
|
||||||
return true;
|
|
||||||
} else if(type instanceof SymbolTypeInline) {
|
|
||||||
return true;
|
return true;
|
||||||
|
} else if (type instanceof SymbolTypeInline) {
|
||||||
|
SymbolTypeInline typeInline = (SymbolTypeInline) type;
|
||||||
|
return typeInline.isByte() || typeInline.isSByte() || typeInline.isWord() || typeInline.isSWord();
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -248,8 +254,8 @@ public class SymbolTypeInference {
|
|||||||
} else if (rValue instanceof ConstantBinary) {
|
} else if (rValue instanceof ConstantBinary) {
|
||||||
ConstantBinary constBin = (ConstantBinary) rValue;
|
ConstantBinary constBin = (ConstantBinary) rValue;
|
||||||
return inferType(symbols, constBin.getLeft(), constBin.getOperator(), constBin.getRight());
|
return inferType(symbols, constBin.getLeft(), constBin.getOperator(), constBin.getRight());
|
||||||
} else if (rValue instanceof ValueArray) {
|
} else if (rValue instanceof ValueList) {
|
||||||
type = inferTypeArray(symbols, (ValueArray)rValue);
|
type = inferTypeList(symbols, (ValueList) rValue);
|
||||||
} else if (rValue instanceof PointerDereference) {
|
} else if (rValue instanceof PointerDereference) {
|
||||||
SymbolType pointerType = inferType(symbols, ((PointerDereference) rValue).getPointer());
|
SymbolType pointerType = inferType(symbols, ((PointerDereference) rValue).getPointer());
|
||||||
if (pointerType instanceof SymbolTypePointer) {
|
if (pointerType instanceof SymbolTypePointer) {
|
||||||
@@ -264,16 +270,16 @@ public class SymbolTypeInference {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SymbolType inferTypeArray(ProgramScope symbols, ValueArray array) {
|
private static SymbolType inferTypeList(ProgramScope symbols, ValueList list) {
|
||||||
SymbolType elmType = null;
|
SymbolType elmType = null;
|
||||||
for (RValue elm : array.getList()) {
|
for (RValue elm : list.getList()) {
|
||||||
SymbolType type = inferType(symbols, elm);
|
SymbolType type = inferType(symbols, elm);
|
||||||
if(elmType==null) {
|
if (elmType == null) {
|
||||||
elmType = type;
|
elmType = type;
|
||||||
} else {
|
} else {
|
||||||
// element type already defined - check for a match
|
// element type already defined - check for a match
|
||||||
if(!typeMatch(elmType, type)) {
|
if (!typeMatch(elmType, type)) {
|
||||||
if(typeMatch(type, elmType)) {
|
if (typeMatch(type, elmType)) {
|
||||||
elmType = type;
|
elmType = type;
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Array element has type mismatch " + elm.toString() + " not matching type " + elmType.getTypeName());
|
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) {
|
if (elmType != null) {
|
||||||
return new SymbolTypeArray(elmType);
|
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 {
|
} 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
|
// Types match directly
|
||||||
return true;
|
return true;
|
||||||
} else if (rValueType instanceof SymbolTypeInline) {
|
} 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
|
// Both are inline types - RValue type must be superset of LValue
|
||||||
Collection<SymbolTypeInteger> lValueTypes = ((SymbolTypeInline) lValueType).getTypes();
|
Collection<SymbolType> lTypes = ((SymbolTypeInline) lValueType).getTypes();
|
||||||
Collection<SymbolTypeInteger> rValueTypes = ((SymbolTypeInline) rValueType).getTypes();
|
return typeContainsMatchAll(lTypes, rTypes);
|
||||||
if(rValueTypes.containsAll(lValueTypes)) {
|
} else {
|
||||||
return true;
|
// Types match because the right side matches the left side
|
||||||
}
|
return typeContainsMatch(lValueType, rTypes);
|
||||||
} else if (((SymbolTypeInline) rValueType).getTypes().contains(lValueType)) {
|
|
||||||
// Types match because the right side is a constant that matches the left side
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
} else if (lValueType instanceof SymbolTypePointer && rValueType instanceof SymbolTypePointer) {
|
} 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)) {
|
} 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 true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -3,21 +3,21 @@ package dk.camelot64.kickc.model;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Symbol Type of an inline numeric expression. Inline expressions can match multiple types depending on the actual value,
|
* 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.
|
* 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 {
|
public class SymbolTypeInline implements SymbolType {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All potential types for the inline constant.
|
* 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;
|
this.types = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<SymbolTypeInteger> getTypes() {
|
public Collection<SymbolType> getTypes() {
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,10 +25,10 @@ public class SymbolTypeInline implements SymbolType {
|
|||||||
public String getTypeName() {
|
public String getTypeName() {
|
||||||
StringBuilder name = new StringBuilder();
|
StringBuilder name = new StringBuilder();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (SymbolTypeInteger type : types) {
|
for (SymbolType type : types) {
|
||||||
if(first) {
|
if (first) {
|
||||||
first = false;
|
first = false;
|
||||||
} else {
|
} else {
|
||||||
name.append("/");
|
name.append("/");
|
||||||
}
|
}
|
||||||
name.append(type);
|
name.append(type);
|
||||||
@@ -38,8 +38,12 @@ public class SymbolTypeInline implements SymbolType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) {
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
SymbolTypeInline that = (SymbolTypeInline) o;
|
SymbolTypeInline that = (SymbolTypeInline) o;
|
||||||
return types != null ? types.equals(that.types) : that.types == null;
|
return types != null ? types.equals(that.types) : that.types == null;
|
||||||
}
|
}
|
||||||
@@ -62,15 +66,28 @@ public class SymbolTypeInline implements SymbolType {
|
|||||||
return types.contains(BYTE);
|
return types.contains(BYTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is signed byte one of the potential types
|
||||||
|
* @return true if signed byte is a potential type
|
||||||
|
*/
|
||||||
public boolean isSByte() {
|
public boolean isSByte() {
|
||||||
return types.contains(SBYTE);
|
return types.contains(SBYTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is unsigned word one of the potential types
|
||||||
|
* @return true if unsigned word is a potential type
|
||||||
|
*/
|
||||||
public boolean isWord() {
|
public boolean isWord() {
|
||||||
return types.contains(WORD);
|
return types.contains(WORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is signed word one of the potential types
|
||||||
|
* @return true if signed word is a potential type
|
||||||
|
*/
|
||||||
public boolean isSWord() {
|
public boolean isSWord() {
|
||||||
return types.contains(SWORD);
|
return types.contains(SWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -2,12 +2,15 @@ package dk.camelot64.kickc.model;
|
|||||||
|
|
||||||
import java.util.List;
|
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. */
|
/** A list of sub-values. Used for array variable initializers and word from byte constructors
|
||||||
public class ValueArray implements RValue {
|
* (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;
|
private List<RValue> list;
|
||||||
|
|
||||||
public ValueArray(List<RValue> list) {
|
public ValueList(List<RValue> list) {
|
||||||
this.list = list;
|
this.list = list;
|
||||||
}
|
}
|
||||||
|
|
@@ -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
|
* Version all uses of non-versioned non-intermediary variables
|
||||||
*/
|
*/
|
||||||
@@ -75,49 +96,13 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||||||
Map<VariableUnversioned, VariableVersion> blockNewPhis = new LinkedHashMap<>();
|
Map<VariableUnversioned, VariableVersion> blockNewPhis = new LinkedHashMap<>();
|
||||||
for (Statement statement : block.getStatements()) {
|
for (Statement statement : block.getStatements()) {
|
||||||
if (statement instanceof StatementReturn) {
|
if (statement instanceof StatementReturn) {
|
||||||
StatementReturn statementReturn = (StatementReturn) statement;
|
execute(new VariableReplacer.ReplacableReturn((StatementReturn) statement), blockVersions, blockNewPhis);
|
||||||
if (statementReturn.getValue() instanceof PointerDereferenceSimple) {
|
} else if (statement instanceof StatementAssignment) {
|
||||||
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) {
|
|
||||||
StatementAssignment assignment = (StatementAssignment) statement;
|
StatementAssignment assignment = (StatementAssignment) statement;
|
||||||
if (assignment.getrValue1() instanceof PointerDereferenceSimple) {
|
execute(new VariableReplacer.ReplacableRValue1(assignment), blockVersions, blockNewPhis);
|
||||||
PointerDereferenceSimple deref = (PointerDereferenceSimple) ((StatementAssignment) statement).getrValue1();
|
execute(new VariableReplacer.ReplacableRValue2(assignment), blockVersions, blockNewPhis);
|
||||||
RValue pointer = deref.getPointer();
|
execute(new VariableReplacer.ReplacableLValue(assignment), blockVersions, blockNewPhis);
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update map of versions encountered in the block
|
// Update map of versions encountered in the block
|
||||||
LValue lValue = assignment.getlValue();
|
LValue lValue = assignment.getlValue();
|
||||||
if (lValue instanceof VariableRef) {
|
if (lValue instanceof VariableRef) {
|
||||||
@@ -127,25 +112,6 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
|||||||
VariableVersion versioned = (VariableVersion) variable;
|
VariableVersion versioned = (VariableVersion) variable;
|
||||||
blockVersions.put(versioned.getVersionOf(), versioned);
|
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -80,9 +80,9 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||||||
if (constant != null) {
|
if (constant != null) {
|
||||||
constants.put(variable, constant);
|
constants.put(variable, constant);
|
||||||
}
|
}
|
||||||
} else if (assignment.getrValue2() instanceof ValueArray && assignment.getOperator() == null && assignment.getrValue1() == null) {
|
} else if (assignment.getrValue2() instanceof ValueList && assignment.getOperator() == null && assignment.getrValue1() == null) {
|
||||||
ValueArray valueArray = (ValueArray) assignment.getrValue2();
|
ValueList valueList = (ValueList) assignment.getrValue2();
|
||||||
List<RValue> values = valueArray.getList();
|
List<RValue> values = valueList.getList();
|
||||||
boolean allConstant = true;
|
boolean allConstant = true;
|
||||||
SymbolType elementType = null;
|
SymbolType elementType = null;
|
||||||
List<ConstantValue> elements = new ArrayList<>();
|
List<ConstantValue> elements = new ArrayList<>();
|
||||||
@@ -94,7 +94,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||||||
elementType = type;
|
elementType = type;
|
||||||
} else {
|
} else {
|
||||||
if (!SymbolTypeInference.typeMatch(type, elementType)) {
|
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);
|
elements.add(constantValue);
|
||||||
|
@@ -48,7 +48,7 @@ public abstract class Pass2SsaOptimization {
|
|||||||
*/
|
*/
|
||||||
public void replaceVariables(final Map<? extends SymbolRef, ? extends RValue> aliases) {
|
public void replaceVariables(final Map<? extends SymbolRef, ? extends RValue> aliases) {
|
||||||
VariableReplacer replacer = new VariableReplacer(aliases);
|
VariableReplacer replacer = new VariableReplacer(aliases);
|
||||||
replacer.getReplacement(getGraph());
|
replacer.execute(getGraph());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -213,9 +213,9 @@ public class Pass3VariableReferenceInfos extends Pass2Base {
|
|||||||
return used;
|
return used;
|
||||||
} else if (rValue instanceof VariableRef) {
|
} else if (rValue instanceof VariableRef) {
|
||||||
return Arrays.asList((VariableRef) rValue);
|
return Arrays.asList((VariableRef) rValue);
|
||||||
} else if (rValue instanceof ValueArray) {
|
} else if (rValue instanceof ValueList) {
|
||||||
LinkedHashSet<VariableRef> used = new LinkedHashSet<>();
|
LinkedHashSet<VariableRef> used = new LinkedHashSet<>();
|
||||||
for (RValue value : ((ValueArray) rValue).getList()) {
|
for (RValue value : ((ValueList) rValue).getList()) {
|
||||||
used.addAll(getReferenced(value));
|
used.addAll(getReferenced(value));
|
||||||
}
|
}
|
||||||
return used;
|
return used;
|
||||||
|
@@ -455,7 +455,7 @@ public class StatementSequenceGenerator extends KickCBaseVisitor<Object> {
|
|||||||
RValue rValue = (RValue) visit(initializer);
|
RValue rValue = (RValue) visit(initializer);
|
||||||
initValues.add(rValue);
|
initValues.add(rValue);
|
||||||
}
|
}
|
||||||
return new ValueArray(initValues);
|
return new ValueList(initValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -2,10 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||||||
|
|
||||||
import dk.camelot64.kickc.model.*;
|
import dk.camelot64.kickc.model.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A replacer capable to alias all usages of a variable (or constant var) with a suitable replacement
|
* 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;
|
this.aliases = aliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getReplacement(ControlFlowGraph graph) {
|
public void execute(ControlFlowGraph graph) {
|
||||||
ControlFlowGraphBaseVisitor<Void> visitor = new GraphReplacer();
|
//new GraphReplacer().visitGraph(graph);
|
||||||
visitor.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.
|
* @return The alias to use. Null if no alias exists.
|
||||||
*/
|
*/
|
||||||
public RValue getReplacement(RValue rValue) {
|
public RValue getReplacement(RValue rValue) {
|
||||||
if(rValue instanceof SymbolRef) {
|
if (rValue instanceof SymbolRef) {
|
||||||
RValue alias = aliases.get(rValue);
|
RValue alias = aliases.get(rValue);
|
||||||
if(alias!=null) {
|
if (alias != null) {
|
||||||
if(alias.equals(rValue)) {
|
if (alias.equals(rValue)) {
|
||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
RValue replacement = getReplacement(alias);
|
RValue replacement = getReplacement(alias);
|
||||||
if(replacement!=null) {
|
if (replacement != null) {
|
||||||
return replacement;
|
return replacement;
|
||||||
} else {
|
} else {
|
||||||
return alias;
|
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 abstract RValue get();
|
||||||
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
|
|
||||||
|
|
||||||
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
|
@Override
|
||||||
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
|
public RValue get() {
|
||||||
if (getReplacement(conditionalJump.getrValue1()) != null) {
|
return statement.getlValue();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitReturn(StatementReturn aReturn) {
|
public void set(RValue value) {
|
||||||
if (getReplacement(aReturn.getValue()) != null) {
|
statement.setlValue((LValue) value);
|
||||||
aReturn.setValue(getReplacement(aReturn.getValue()));
|
}
|
||||||
} else {
|
|
||||||
if (aReturn.getValue() instanceof PointerDereferenceSimple) {
|
}
|
||||||
PointerDereferenceSimple deref = (PointerDereferenceSimple) aReturn.getValue();
|
|
||||||
RValue pointer = deref.getPointer();
|
/** Replacable pointer inside a pointer dererence value. */
|
||||||
if (getReplacement(pointer) != null) {
|
public static class ReplacablePointer extends ReplacableValue {
|
||||||
deref.setPointer(getReplacement(pointer));
|
private final PointerDereference pointer;
|
||||||
}
|
|
||||||
}
|
ReplacablePointer(PointerDereference pointer) {
|
||||||
}
|
this.pointer = pointer;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitCall(StatementCall call) {
|
public RValue get() {
|
||||||
if (call.getParameters() != null) {
|
return pointer.getPointer();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitPhiBlock(StatementPhiBlock phi) {
|
public void set(RValue val) {
|
||||||
for (StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
|
pointer.setPointer(val);
|
||||||
if (getReplacement(phiVariable.getVariable()) != null) {
|
}
|
||||||
RValue alias = getReplacement(phiVariable.getVariable());
|
|
||||||
if (alias instanceof LValue) {
|
}
|
||||||
phiVariable.setVariable((VariableRef) alias);
|
|
||||||
}
|
public static class ReplacableListElement extends ReplacableValue {
|
||||||
}
|
private ValueList list;
|
||||||
List<StatementPhiBlock.PhiRValue> phirValues = phiVariable.getValues();
|
private int idx;
|
||||||
Iterator<StatementPhiBlock.PhiRValue> it = phirValues.iterator();
|
|
||||||
while (it.hasNext()) {
|
public ReplacableListElement(ValueList list, int idx) {
|
||||||
StatementPhiBlock.PhiRValue phirValue = it.next();
|
this.list = list;
|
||||||
if (getReplacement(phirValue.getrValue()) != null) {
|
this.idx = idx;
|
||||||
RValue alias = getReplacement(phirValue.getrValue());
|
}
|
||||||
if (LValue.VOID.equals(alias)) {
|
|
||||||
it.remove();
|
@Override
|
||||||
} else {
|
public RValue get() {
|
||||||
phirValue.setrValue(alias);
|
return list.getList().get(idx);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if(phirValue.getrValue() instanceof PointerDereferenceSimple) {
|
@Override
|
||||||
PointerDereferenceSimple deref = (PointerDereferenceSimple) phirValue.getrValue();
|
public void set(RValue value) {
|
||||||
RValue pointer = deref.getPointer();
|
list.getList().set(idx, value);
|
||||||
if (getReplacement(pointer) != null) {
|
}
|
||||||
deref.setPointer(getReplacement(pointer));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
/** Replacable pointer index inside a indexed pointer dererence value. */
|
||||||
}
|
public static class ReplacablePointerIndex extends ReplacableValue {
|
||||||
}
|
private final PointerDereferenceIndexed pointer;
|
||||||
return null;
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,10 @@ public class TestPrograms extends TestCase {
|
|||||||
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
|
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testInlineWord() throws IOException, URISyntaxException {
|
||||||
|
compileAndCompare("inline-word");
|
||||||
|
}
|
||||||
|
|
||||||
public void testSignedWords() throws IOException, URISyntaxException {
|
public void testSignedWords() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("signed-words");
|
compileAndCompare("signed-words");
|
||||||
}
|
}
|
||||||
@@ -183,6 +187,10 @@ public class TestPrograms extends TestCase {
|
|||||||
compileAndCompare("inmemarray");
|
compileAndCompare("inmemarray");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testInMemConstArray() throws IOException, URISyntaxException {
|
||||||
|
compileAndCompare("inmem-const-array");
|
||||||
|
}
|
||||||
|
|
||||||
public void testInMemString() throws IOException, URISyntaxException {
|
public void testInMemString() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("inmemstring");
|
compileAndCompare("inmemstring");
|
||||||
}
|
}
|
||||||
|
12
src/main/java/dk/camelot64/kickc/test/inline-word.kc
Normal file
12
src/main/java/dk/camelot64/kickc/test/inline-word.kc
Normal 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 = '*';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
src/main/java/dk/camelot64/kickc/test/inmem-const-array.kc
Normal file
18
src/main/java/dk/camelot64/kickc/test/inmem-const-array.kc
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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
|
||||||
|
}
|
@@ -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
|
1828
src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.log
Normal file
1828
src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.log
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 ]
|
Reference in New Issue
Block a user