mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-04 00:30:43 +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:
parent
eb6ee9bff8
commit
e314794f0b
@ -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()) {
|
||||
|
@ -5,4 +5,7 @@ public interface PointerDereference extends LValue {
|
||||
|
||||
RValue getPointer();
|
||||
|
||||
void setPointer(RValue pointer);
|
||||
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
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 ]
|
Loading…
x
Reference in New Issue
Block a user