1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-01-08 13:31:03 +00:00

New literal word constructor handling - 277/354

This commit is contained in:
jespergravgaard 2019-05-12 21:18:55 +02:00
parent 07b67efb7c
commit fe60b31f73
13 changed files with 174 additions and 116 deletions

View File

@ -254,6 +254,7 @@ public class Compiler {
optimizations.add(new Pass2ConstantIfs(program));
optimizations.add(new Pass2ConstantStringConsolidation(program));
optimizations.add(new Pass2FixInlineConstructors(program));
optimizations.add(new Pass2FixInlineConstructorsNew(program));
optimizations.add(new Pass2TypeInference(program));
optimizations.add(new PassNEliminateUnusedVars(program, true));
optimizations.add(new Pass2EliminateRedundantCasts(program));

View File

@ -5,9 +5,7 @@ import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
import dk.camelot64.kickc.model.values.ConstantBinary;
import dk.camelot64.kickc.model.values.ConstantUnary;
import dk.camelot64.kickc.model.values.PointerDereferenceIndexed;
import dk.camelot64.kickc.model.values.*;
import java.util.ListIterator;
@ -33,6 +31,8 @@ public class ProgramExpressionIterator {
handler.execute(new ProgramExpressionUnary.ProgramExpressionUnaryConstant(programValue), null, null, null);
} else if(programValue.get() instanceof PointerDereferenceIndexed) {
handler.execute(new ProgramExpressionBinary.ProgramExpressionBinaryPointerDereferenceIndexed(programValue), null, null, null);
} else if(programValue.get() instanceof ConstantCastValue) {
handler.execute(new ProgramExpressionUnary.ProgramExpressionUnaryCast(programValue), null, null, null);
}
};
ProgramValueIterator.execute(program.getScope(), programValueHandler);

View File

@ -1,7 +1,9 @@
package dk.camelot64.kickc.model.iterator;
import dk.camelot64.kickc.model.operators.OperatorUnary;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.values.ConstantCastValue;
import dk.camelot64.kickc.model.values.ConstantUnary;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.Value;
@ -52,7 +54,7 @@ public interface ProgramExpressionUnary extends ProgramExpression {
/** Unary expression as part of a constant expression. */
class ProgramExpressionUnaryConstant implements ProgramExpressionUnary {
/** A ProgramValue containing a {@link ConstantUnary}. */
private ProgramValue programValue;
@ -81,4 +83,37 @@ public interface ProgramExpressionUnary extends ProgramExpression {
}
/** Unary cast expression {@link ConstantCastValue} as part of a constant expression. */
class ProgramExpressionUnaryCast implements ProgramExpressionUnary {
/** A ProgramValue containing a {@link ConstantCastValue}. */
private ProgramValue programValue;
ProgramExpressionUnaryCast(ProgramValue programValue) {
this.programValue = programValue;
}
public ConstantCastValue getConstantUnary() {
return (ConstantCastValue) programValue.get();
}
@Override
public OperatorUnary getOperator() {
return Operators.getCastUnary(getConstantUnary().getToType());
}
@Override
public RValue getOperand() {
return getConstantUnary().getValue();
}
@Override
public void set(Value value) {
programValue.set(value);
}
}
}

View File

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

View File

@ -9,10 +9,6 @@ import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.values.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Type inference of expressions (rValues & unary/binary operators)
*/
@ -126,7 +122,7 @@ public class SymbolTypeInference {
} else if(rValue instanceof ProcedureRef) {
Procedure procedure = symbols.getProcedure((ProcedureRef) rValue);
return procedure.getType();
} else if(rValue instanceof AssignmentRValue) {
} else if(rValue instanceof AssignmentRValue) {
return inferTypeRValue(symbols, ((AssignmentRValue) rValue).getAssignment());
}
if(type == null) {
@ -148,21 +144,8 @@ public class SymbolTypeInference {
}
}
if(elmType != null) {
if((list.getList().size() == 2 && SymbolType.BYTE.equals(elmType) || SymbolType.SBYTE.equals(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 SymbolTypeMulti(types);
} else if((list.getList().size() == 2 && SymbolType.WORD.equals(elmType))) {
// Potentially a dword constructor - return a composite type
ArrayList<SymbolType> types = new ArrayList<>();
types.add(new SymbolTypeArray(elmType));
types.add(SymbolType.DWORD);
return new SymbolTypeMulti(types);
} else {
return new SymbolTypeArray(elmType);
}
long size = list.getList().size();
return new SymbolTypeArray(elmType, new ConstantInteger(size, size<256?SymbolType.BYTE:SymbolType.WORD));
} else {
throw new RuntimeException("Cannot infer list element type " + list.toString());
}
@ -223,13 +206,8 @@ public class SymbolTypeInference {
SymbolType valueType = inferType(programScope, rValue);
if(type == null) {
type = valueType;
} else {
SymbolType newType = intersectTypes(type, valueType);
if(newType == null) {
throw new CompileError("Types not compatible " + type + " and " + valueType);
}
type = newType;
}
} else if(!type.equals(valueType))
throw new CompileError("Types not compatible " + type + " and " + valueType);
}
if(!SymbolType.VAR.equals(symbol.getType()) && !type.equals(symbol.getType())) {
program.getLog().append("Inferred type updated to " + type + " for " + symbol.toString(program));
@ -295,53 +273,4 @@ public class SymbolTypeInference {
}
}
/**
* Find the symbol type that is the intersection between the two passed types.
* Handles SymbolTypeMulti by intersecting the sub type lists.
*
* @param type1 The first type
* @param type2 The second type
* @return The intersection between the two types (handling multi-types)
*/
public static SymbolType intersectTypes(SymbolType type1, SymbolType type2) {
List<SymbolType> newSubTypes = new ArrayList<>();
if(type1 instanceof SymbolTypeMulti) {
Collection<SymbolType> subTypes1 = ((SymbolTypeMulti) type1).getTypes();
if(type2 instanceof SymbolTypeMulti) {
Collection<SymbolType> subTypes2 = ((SymbolTypeMulti) type2).getTypes();
for(SymbolType subType1 : subTypes1) {
if(subTypes2.contains(subType1)) {
newSubTypes.add(subType1);
}
}
} else {
// Element type is not multi - check if the list type contains it
if(subTypes1.contains(type2)) {
newSubTypes.add(type2);
}
}
} else {
// List-type not multi - check if the element type contains it
if(type2 instanceof SymbolTypeMulti) {
Collection<SymbolType> subTypes2 = ((SymbolTypeMulti) type2).getTypes();
if(subTypes2.contains(type1)) {
newSubTypes.add(type1);
}
} else {
// Element type is not multi - check if the list type is the same
if(type1.equals(type2)) {
newSubTypes.add(type1);
}
}
}
if(newSubTypes.size() == 0) {
return null;
} else if(newSubTypes.size() == 1) {
// A single type matching - use it
return newSubTypes.get(0);
} else {
// Multiple matches was found - use them
return new SymbolTypeMulti(newSubTypes);
}
}
}

View File

@ -38,4 +38,8 @@ public class ValueList implements RValue {
return out.toString();
}
@Override
public String toString() {
return toString(null);
}
}

View File

@ -53,37 +53,6 @@ public class Pass2ConstantCastSimplification extends Pass2SsaOptimization {
}
}
});
ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> {
if(programValue.get() instanceof ConstantCastValue) {
ConstantCastValue constantCastValue = (ConstantCastValue) programValue.get();
if(constantCastValue.getValue() instanceof ConstantInteger) {
ConstantInteger constantInteger = (ConstantInteger) constantCastValue.getValue();
SymbolType castType = constantCastValue.getToType();
if(SymbolType.NUMBER.equals(constantInteger.getType())) {
if(castType instanceof SymbolTypeIntegerFixed ) {
ConstantInteger newConstInt = new ConstantInteger(constantInteger.getInteger(), castType);
programValue.set(newConstInt);
getLog().append("Simplifying constant integer cast " + newConstInt.toString());
optimized.set(true);
} else if(castType instanceof SymbolTypePointer) {
ConstantPointer newConstPointer = new ConstantPointer(constantInteger.getInteger(), ((SymbolTypePointer) castType).getElementType());
programValue.set(newConstPointer);
getLog().append("Simplifying constant pointer cast " + newConstPointer.toString());
optimized.set(true);
}
} else if(castType instanceof SymbolTypeIntegerFixed) {
if(((SymbolTypeIntegerFixed) castType).contains(constantInteger.getValue())) {
// Cast type contains the value - cast not needed
ConstantInteger newConstInt = new ConstantInteger(constantInteger.getInteger(), castType);
programValue.set(newConstInt);
getLog().append("Simplifying constant integer cast " + newConstInt.toString());
optimized.set(true);
}
}
}
}
});
return optimized.get();
}

View File

@ -0,0 +1,69 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.Comment;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramExpressionIterator;
import dk.camelot64.kickc.model.iterator.ProgramExpressionUnary;
import dk.camelot64.kickc.model.operators.OperatorBinary;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.VariableIntermediate;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.CastValue;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.ValueList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Identifies word constructors <code> (word) { b1, b2 }</code> and replaces
* them with a binary operator <code>word w = b1 w= b2 ;</code>
*/
public class Pass2FixInlineConstructorsNew extends Pass2SsaOptimization {
public Pass2FixInlineConstructorsNew(Program program) {
super(program);
}
@Override
public boolean step() {
AtomicBoolean optimized = new AtomicBoolean(false);
ProgramExpressionIterator.execute(getProgram(), (programExpression, currentStmt, stmtIt, currentBlock) -> {
if(programExpression instanceof ProgramExpressionUnary) {
if(programExpression.getOperator().equals(Operators.CAST_WORD)) {
if(((ProgramExpressionUnary) programExpression).getOperand() instanceof ValueList) {
ValueList list = (ValueList) ((ProgramExpressionUnary) programExpression).getOperand();
List<RValue> listValues = list.getList();
if(listValues.size()==2) {
OperatorBinary constructOperator = Operators.WORD;
SymbolType constructType = SymbolType.WORD;
// Convert list to a word constructor in a new tmp variable
Scope currentScope = Pass2FixInlineConstructorsNew.this.getScope().getScope(currentBlock.getScope());
VariableIntermediate tmpVar = currentScope.addVariableIntermediate();
tmpVar.setTypeInferred(constructType);
// Move backward - to insert before the current statement
stmtIt.previous();
// Add assignment of the new tmpVar
StatementAssignment assignment = new StatementAssignment(tmpVar.getRef(), new CastValue(SymbolType.BYTE, listValues.get(0)), constructOperator, new CastValue(SymbolType.BYTE, listValues.get(1)), currentStmt.getSource(), Comment.NO_COMMENTS);
stmtIt.add(assignment);
// Move back before the current statement
stmtIt.next();
// Replace current value with the reference
programExpression.set(tmpVar.getRef());
Pass2FixInlineConstructorsNew.this.getLog().append("Fixing inline constructor with " + assignment.toString());
optimized.set(true);
}
}
}
}
});
return optimized.get();
}
}

View File

@ -4,6 +4,7 @@ import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramExpressionBinary;
import dk.camelot64.kickc.model.iterator.ProgramExpressionIterator;
import dk.camelot64.kickc.model.types.*;
import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.RValue;
import java.util.concurrent.atomic.AtomicBoolean;
@ -37,6 +38,15 @@ public class PassNAddTypeConversionAssignment extends Pass2SsaOptimization {
binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope());
modified.set(true);
}
// Detect word literal constructor
if(leftType.equals(SymbolType.WORD) && isLiteralWordCandidate(rightType)) {
SymbolType conversionType = SymbolType.WORD;
getLog().append("Identified literal word (" + conversionType + ") " + binary.getRight().toString() + " in " + (currentStmt == null ? "" : currentStmt.toString(getProgram(), false)));
binary.addRightCast(SymbolType.WORD, stmtIt, currentBlock == null ? null : currentBlock.getScope(), getScope());
modified.set(true);
}
}
if(leftType instanceof SymbolTypeIntegerFixed && SymbolType.isInteger(rightType)) {
SymbolType conversionType = SymbolTypeConversion.convertedMathType((SymbolTypeInteger) leftType, (SymbolTypeInteger) rightType);
@ -53,5 +63,14 @@ public class PassNAddTypeConversionAssignment extends Pass2SsaOptimization {
return modified.get();
}
public static boolean isLiteralWordCandidate(SymbolType rightType) {
if(rightType instanceof SymbolTypeArray) {
SymbolTypeArray rightArray = (SymbolTypeArray) rightType;
if(new ConstantInteger(2L, SymbolType.BYTE).equals(rightArray.getSize()))
if(SymbolType.BYTE.equals(rightArray.getElementType()) || SymbolType.NUMBER.equals(rightArray.getElementType()))
return true;
}
return false;
}
}

View File

@ -1359,6 +1359,21 @@ public class TestPrograms {
compileAndCompare("inline-assignment");
}
@Test
public void testInlineWord0() throws IOException, URISyntaxException {
compileAndCompare("inline-word-0");
}
@Test
public void testInlineWord1() throws IOException, URISyntaxException {
compileAndCompare("inline-word-1");
}
@Test
public void testInlineWord2() throws IOException, URISyntaxException {
compileAndCompare("inline-word-2");
}
@Test
public void testInlineWord() throws IOException, URISyntaxException {
compileAndCompare("inline-word");

View File

@ -0,0 +1,7 @@
// Tests minimal inline word
void main() {
word w = { 0x02ub, 0x01ub };
word* screen = 0x0400;
screen[0] = w;
}

View File

@ -0,0 +1,7 @@
// Tests minimal inline word
void main() {
word w = { 0x01, 0x02 };
word* screen = 0x0400;
screen[0] = w;
}

View File

@ -0,0 +1,7 @@
// Tests minimal inline word
void main() {
word w = { 0x01, 0x02ub };
word* screen = 0x0400;
screen[0] = w;
}