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:
parent
e56e66acd8
commit
6e566852ba
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()) +
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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)
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user