1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-20 02:32:36 +00:00

Fixed assignment type conversions and unnecesary byte/word casts. 269/351

This commit is contained in:
jespergravgaard 2019-05-12 12:27:48 +02:00
parent e56e66acd8
commit 6e566852ba
9 changed files with 115 additions and 117 deletions

View File

@ -165,7 +165,7 @@ public class Compiler {
new Pass1FixLValuesLoHi(program).execute();
new Pass1AssertNoLValueIntermediate(program).execute();
new Pass1PointerSizeofFix(program).execute();
new PassNAddTypeConversionsNew(program).execute();
new PassNAddTypeConversionAssignment(program).execute();
new Pass1EarlyConstantIdentification(program).execute();
new PassNStatementIndices(program).step();
new PassNCallGraphAnalysis(program).step();
@ -231,7 +231,7 @@ public class Compiler {
private void pass2Optimize() {
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
optimizations.add(new PassNAddTypeConversionsNew(program));
optimizations.add(new PassNAddTypeConversionAssignment(program));
optimizations.add(new PassNAddNumberTypeConversions(program));
optimizations.add(new PassNDowngradeBytePlusWord(program));
optimizations.add(new PassNTypeInference(program));

View File

@ -85,6 +85,7 @@ public class SymbolTypeConversion {
if(leftType instanceof SymbolTypePointer) leftType = SymbolType.WORD;
if(rightType instanceof SymbolTypePointer) rightType = SymbolType.WORD;
// Identify which of the two operands is a number and which is a fixed type
RValue numberVal;
SymbolTypeIntegerFixed fixedType;
if(SymbolType.NUMBER.equals(leftType) && SymbolType.isInteger(rightType)) {
@ -95,19 +96,12 @@ public class SymbolTypeConversion {
// Right is the number type - left is the fixed type
numberVal = right;
fixedType = (SymbolTypeIntegerFixed) leftType;
} else if(SymbolType.NUMBER.equals(leftType) && rightType instanceof SymbolTypePointer) {
// Left is the number type - right is a pointer (effectively unsigned word)
numberVal = left;
fixedType = SymbolType.WORD;
} else if(SymbolType.NUMBER.equals(rightType) && leftType instanceof SymbolTypePointer) {
// Right is the number type - left is a pointer (effectively unsigned word)
numberVal = right;
fixedType = SymbolType.WORD;
} else {
// Binary operator combining number and non-integer
return null;
}
// Find the cast type if possible
if(numberVal instanceof ConstantValue) {
ConstantLiteral constantLiteral = ((ConstantValue) numberVal).calculateLiteral(symbols);
if(constantLiteral instanceof ConstantInteger) {
@ -115,14 +109,14 @@ public class SymbolTypeConversion {
if(SymbolType.NUMBER.equals(constantInteger.getType())) {
Long value = constantInteger.getValue();
if(fixedType.isSigned()) {
// b) If one operand is a signed type and the other a number they are both converted to the smallest signed type that can hold the values.
// b) If one operand is a signed type and the other a number the number is converted to the smallest signed type that can hold its values.
SymbolTypeIntegerFixed smallestSignedType = SymbolTypeIntegerFixed.getSmallestSigned(value);
if(smallestSignedType == null) {
throw new CompileError("Number constant has value that cannot be represented by a signed type " + value, currentStmt);
}
return smallestSignedType.getBits() > fixedType.getBits() ? smallestSignedType : fixedType;
return smallestSignedType;
} else {
// c) If one operand is an unsigned type and the other a number they are both converted to the smallest unsigned type that can hold the values.
// b) If one operand is a signed type and the other a number the number is converted to the smallest unsigned type that can hold its values.
// If the number value is negative it is converted to unsigned using two's complement.
SymbolTypeIntegerFixed smallestUnsignedType;
if(value < 0) {
@ -131,7 +125,6 @@ public class SymbolTypeConversion {
smallestUnsignedType = SymbolTypeIntegerFixed.getSmallestUnsigned(value);
}
return smallestUnsignedType;
//return smallestUnsignedType.getBits() > fixedType.getBits() ? smallestUnsignedType : fixedType;
}
} else {
throw new InternalError("Non-number constant has type number " + right.toString(), currentStmt);
@ -145,4 +138,33 @@ public class SymbolTypeConversion {
// No number conversion
return null;
}
/**
* Determines if the types of an assignment match up properly
* @param lValueType The type of the LValue
* @param rValueType The type of the RValue
* @return true if the types match up
*/
public static boolean assignmentTypeMatch(SymbolType lValueType, SymbolType rValueType) {
if(lValueType.equals(rValueType))
return true;
if(lValueType.equals(SymbolType.WORD) && rValueType.equals(SymbolType.BYTE))
return true;
if(lValueType.equals(SymbolType.SWORD) && rValueType.equals(SymbolType.SBYTE))
return true;
if(SymbolType.NUMBER.equals(rValueType) && SymbolType.isInteger(lValueType)) {
// L-value is still a number - constants are probably not done being identified & typed
return true;
}
if(SymbolType.STRING.equals(rValueType) && lValueType instanceof SymbolTypePointer && ((SymbolTypePointer) lValueType).getElementType().equals(SymbolType.BYTE)) {
// String value can be assigned into a pointer
return true;
}
if(lValueType instanceof SymbolTypePointer && rValueType instanceof SymbolTypePointer && assignmentTypeMatch(((SymbolTypePointer) lValueType).getElementType(), ((SymbolTypePointer) rValueType).getElementType())) {
// Pointer types assigned from each other
// TODO: Maybe handle sizes
return true;
}
return false;
}
}

View File

@ -1,31 +0,0 @@
package dk.camelot64.kickc.model.types;
/** Container for function checking if types of an assignment match up */
public class SymbolTypeMatch {
/**
* Determines if the types of an assignment match up properly
* @param lValueType The type of the LValue
* @param rValueType The type of the RValue
* @return true if the types match up
*/
public static boolean assignmentTypeMatch(SymbolType lValueType, SymbolType rValueType) {
if(lValueType.equals(rValueType)) {
return true;
}
if(SymbolType.NUMBER.equals(rValueType) && SymbolType.isInteger(lValueType)) {
// L-value is still a number - constants are probably not done being identified & typed
return true;
}
if(SymbolType.STRING.equals(rValueType) && lValueType instanceof SymbolTypePointer && ((SymbolTypePointer) lValueType).getElementType().equals(SymbolType.BYTE)) {
// String value can be assigned into a pointer
return true;
}
if(lValueType instanceof SymbolTypePointer && rValueType instanceof SymbolTypePointer && assignmentTypeMatch(((SymbolTypePointer) lValueType).getElementType(), ((SymbolTypePointer) rValueType).getElementType())) {
// Pointer types assigned from each other
// TODO: Maybe handle sizes
return true;
}
return false;
}
}

View File

@ -7,8 +7,8 @@ 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.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeConversion;
import dk.camelot64.kickc.model.types.SymbolTypeInference;
import dk.camelot64.kickc.model.types.SymbolTypeMatch;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.RValue;
@ -51,7 +51,7 @@ public class Pass2AssertTypeMatch extends Pass2SsaAssertion {
LValue lValue = statement.getlValue();
SymbolType lValueType = SymbolTypeInference.inferType(getScope(), lValue);
SymbolType rValueType = SymbolTypeInference.inferTypeRValue(getScope(), statement);
if(SymbolTypeMatch.assignmentTypeMatch(lValueType, rValueType)) return;
if(SymbolTypeConversion.assignmentTypeMatch(lValueType, rValueType)) return;
// Types do not match
getLog().append("ERROR! Type mismatch (" + lValueType.getTypeName() + ") cannot be assigned from (" + rValueType.getTypeName() + "). In " + statement.toString(getProgram(), false));
throw new CompileError("ERROR! Type mismatch (" + lValueType.getTypeName() + ") cannot be assigned from (" + rValueType.getTypeName() + "). In " + statement.toString(getProgram(), false), statement.getSource());

View File

@ -28,10 +28,10 @@ public class Pass2ConstantCastSimplification extends Pass2SsaOptimization {
if(programExpression.getOperator() instanceof OperatorCast) {
OperatorCast operatorCast = (OperatorCast) programExpression.getOperator();
ProgramExpressionUnary unary = (ProgramExpressionUnary) programExpression;
SymbolType castType = operatorCast.getToType();
if(unary.getOperand() instanceof ConstantInteger) {
ConstantInteger constantInteger = (ConstantInteger) unary.getOperand();
if(SymbolType.NUMBER.equals(constantInteger.getType())) {
SymbolType castType = operatorCast.getToType();
if(castType instanceof SymbolTypeIntegerFixed ) {
ConstantInteger newConstInt = new ConstantInteger(constantInteger.getInteger(), castType);
programExpression.set(newConstInt);
@ -43,6 +43,14 @@ public class Pass2ConstantCastSimplification extends Pass2SsaOptimization {
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);
programExpression.set(newConstInt);
getLog().append("Simplifying constant integer cast " + newConstInt.toString());
optimized.set(true);
}
}
}
}
@ -52,8 +60,8 @@ public class Pass2ConstantCastSimplification extends Pass2SsaOptimization {
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())) {
SymbolType castType = constantCastValue.getToType();
if(castType instanceof SymbolTypeIntegerFixed ) {
ConstantInteger newConstInt = new ConstantInteger(constantInteger.getInteger(), castType);
programValue.set(newConstInt);
@ -65,6 +73,14 @@ public class Pass2ConstantCastSimplification extends Pass2SsaOptimization {
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);
}
}
}
}

View File

@ -15,8 +15,8 @@ import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeConversion;
import dk.camelot64.kickc.model.types.SymbolTypeInference;
import dk.camelot64.kickc.model.types.SymbolTypeMatch;
import dk.camelot64.kickc.model.values.*;
import java.util.LinkedHashMap;
@ -79,7 +79,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
continue;
}
if(!SymbolTypeMatch.assignmentTypeMatch(variableType, valueType)) {
if(!SymbolTypeConversion.assignmentTypeMatch(variableType, valueType)) {
throw new CompileError(
"Constant variable has a non-matching type \n variable: " + variable.toString(getProgram()) +
"\n value: (" + valueType.toString() + ") " + constVal.calculateLiteral(getScope()) +

View File

@ -0,0 +1,57 @@
package dk.camelot64.kickc.passes;
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.RValue;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Add a cast a variable is assigned something of a convertible type.
* Also allows pointers to be assigned integer values.
*/
public class PassNAddTypeConversionAssignment extends Pass2SsaOptimization {
public PassNAddTypeConversionAssignment(Program program) {
super(program);
}
@Override
public boolean step() {
AtomicBoolean modified = new AtomicBoolean(false);
ProgramExpressionIterator.execute(getProgram(), (programExpression, currentStmt, stmtIt, currentBlock) -> {
if(programExpression instanceof ProgramExpressionBinary) {
ProgramExpressionBinary binary = (ProgramExpressionBinary) programExpression;
RValue left = binary.getLeft();
RValue right = binary.getRight();
SymbolType leftType = SymbolTypeInference.inferType(getProgram().getScope(), left);
SymbolType rightType = SymbolTypeInference.inferType(getProgram().getScope(), right);
if(!SymbolTypeConversion.assignmentTypeMatch(leftType, rightType)) {
// Assigning a pointer from an unsigned word
if(programExpression instanceof ProgramExpressionBinary.ProgramExpressionBinaryAssignmentLValue) {
if((leftType instanceof SymbolTypePointer) && SymbolType.isInteger(rightType)) {
getLog().append("Adding pointer type conversion cast (" + leftType + ") " + binary.getLeft().toString() + " in " + currentStmt.toString(getProgram(), false));
binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope());
modified.set(true);
}
}
if(leftType instanceof SymbolTypeIntegerFixed && SymbolType.isInteger(rightType)) {
SymbolType conversionType = SymbolTypeConversion.convertedMathType((SymbolTypeInteger) leftType, (SymbolTypeInteger) rightType);
// Add cast to the right Type if needed
if(leftType.equals(conversionType) && !rightType.equals(conversionType)) {
getLog().append("Adding type conversion cast (" + conversionType + ") " + binary.getRight().toString() + " in " + (currentStmt == null ? "" : currentStmt.toString(getProgram(), false)));
binary.addRightCast(conversionType, stmtIt, currentBlock == null ? null : currentBlock.getScope(), getScope());
modified.set(true);
}
}
}
}
});
return modified.get();
}
}

View File

@ -1,65 +0,0 @@
package dk.camelot64.kickc.passes;
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.RValue;
/**
* Add casts in binary expressions where left/right types are not equal according to the C99 type conversion rules
* 6.3.1.8 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=70.
*/
public class PassNAddTypeConversionsNew extends Pass2SsaOptimization {
public PassNAddTypeConversionsNew(Program program) {
super(program);
}
@Override
public boolean step() {
ProgramExpressionIterator.execute(getProgram(), (programExpression, currentStmt, stmtIt, currentBlock) -> {
if(programExpression instanceof ProgramExpressionBinary) {
ProgramExpressionBinary binary = (ProgramExpressionBinary) programExpression;
RValue left = binary.getLeft();
RValue right = binary.getRight();
SymbolType leftType = SymbolTypeInference.inferType(getProgram().getScope(), left);
SymbolType rightType = SymbolTypeInference.inferType(getProgram().getScope(), right);
// Special handling of assigning a pointer from an unsigned word
if((programExpression instanceof ProgramExpressionBinary.ProgramExpressionBinaryAssignmentLValue) && (leftType instanceof SymbolTypePointer) && SymbolType.isInteger(rightType)) {
getLog().append("Adding pointer type conversion cast (" + leftType + ") " + binary.getLeft().toString() + " in " + currentStmt.toString(getProgram(), false));
binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope());
}
/*
if(SymbolType.isInteger(leftType) && SymbolType.isInteger(rightType)) {
SymbolType conversionType = SymbolTypeConversion.convertedMathType((SymbolTypeInteger) leftType, (SymbolTypeInteger) rightType);
if(conversionType != null && !SymbolType.NUMBER.equals(conversionType)) {
// If byte-like + word-like - skip!!
if(leftType.equals(SymbolType.WORD) && rightType.equals(SymbolType.BYTE)) {
return;
}
if(rightType.equals(SymbolType.WORD) && leftType.equals(SymbolType.BYTE)) {
return;
}
// Convert both left and right to the found type
if(!leftType.equals(conversionType)) {
getLog().append("Adding type conversion cast (" + conversionType + ") " + binary.getLeft().toString() + " in " + currentStmt.toString(getProgram(), false));
binary.addLeftCast(conversionType, stmtIt, currentBlock.getScope(), getScope());
}
if(!rightType.equals(conversionType)) {
getLog().append("Adding type conversion cast (" + conversionType + ") " + binary.getRight().toString() + " in " + currentStmt.toString(getProgram(), false));
binary.addRightCast(conversionType, stmtIt, currentBlock.getScope(), getScope());
}
}
}
*/
}
});
return false;
}
}

View File

@ -42,7 +42,6 @@ public class PassNDowngradeBytePlusWord extends Pass2SsaOptimization {
return modified.get();
}
/**
* Determines if a constant value is a byte-like value (can be represented inside a BYTE)
*