diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index fd5051bd2..fcfc80bcb 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -232,12 +232,15 @@ public class Compiler { private List getPass2Optimizations() { List optimizations = new ArrayList<>(); optimizations.add(new Pass2FixInlineConstructorsNew(program)); + optimizations.add(new PassNAddNumberTypeConversions(program)); optimizations.add(new PassNAddArrayNumberTypeConversions(program)); - optimizations.add(new PassNTypeInference(program)); - optimizations.add(new PassNAddTypeConversionAssignment(program)); optimizations.add(new Pass2InlineCast(program)); optimizations.add(new PassNCastSimplification(program)); + optimizations.add(new PassNFinalizeNumberTypeConversions(program)); + optimizations.add(new PassNTypeInference(program)); + optimizations.add(new PassNAddTypeConversionAssignment(program)); + optimizations.add(new PassNTypeIdSimplification(program)); optimizations.add(new Pass2SizeOfSimplification(program)); optimizations.add(new PassNStatementIndices(program)); diff --git a/src/main/java/dk/camelot64/kickc/model/iterator/ProgramExpressionBinary.java b/src/main/java/dk/camelot64/kickc/model/iterator/ProgramExpressionBinary.java index e0b959796..f21ea8348 100644 --- a/src/main/java/dk/camelot64/kickc/model/iterator/ProgramExpressionBinary.java +++ b/src/main/java/dk/camelot64/kickc/model/iterator/ProgramExpressionBinary.java @@ -10,6 +10,7 @@ import dk.camelot64.kickc.model.statements.StatementConditionalJump; import dk.camelot64.kickc.model.statements.StatementPhiBlock; 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.symbols.VariableIntermediate; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypeInference; @@ -96,7 +97,7 @@ public interface ProgramExpressionBinary extends ProgramExpression { } else { Scope blockScope = symbols.getScope(currentScope); VariableIntermediate tmpVar = blockScope.addVariableIntermediate(); - tmpVar.setType(toType); + tmpVar.setTypeInferred(toType); StatementAssignment newAssignment = new StatementAssignment(tmpVar.getRef(), Operators.getCastUnary(toType), assignment.getrValue1(), assignment.getSource(), Comment.NO_COMMENTS); assignment.setrValue1(tmpVar.getRef()); stmtIt.previous(); @@ -112,7 +113,7 @@ public interface ProgramExpressionBinary extends ProgramExpression { } else { Scope blockScope = symbols.getScope(currentScope); VariableIntermediate tmpVar = blockScope.addVariableIntermediate(); - tmpVar.setType(toType); + tmpVar.setTypeInferred(toType); StatementAssignment newAssignment = new StatementAssignment(tmpVar.getRef(), Operators.getCastUnary(toType), assignment.getrValue2(), assignment.getSource(), Comment.NO_COMMENTS); assignment.setrValue2(tmpVar.getRef()); stmtIt.previous(); @@ -156,13 +157,21 @@ public interface ProgramExpressionBinary extends ProgramExpression { @Override public void addLeftCast(SymbolType toType, ListIterator stmtIt, ScopeRef currentScope, ProgramScope symbols) { - Scope blockScope = symbols.getScope(currentScope); - VariableIntermediate tmpVar = blockScope.addVariableIntermediate(); - SymbolType rightType = SymbolTypeInference.inferType(symbols, getRight()); - tmpVar.setType(rightType); - StatementAssignment newAssignment = new StatementAssignment(assignment.getlValue(), Operators.getCastUnary(toType), tmpVar.getRef(), assignment.getSource(), Comment.NO_COMMENTS); - assignment.setlValue(tmpVar.getRef()); - stmtIt.add(newAssignment); + if(assignment.getlValue() instanceof VariableRef) { + Variable variable = symbols.getVariable((VariableRef) assignment.getlValue()); + if(variable.isInferredType()) + variable.setTypeInferred(toType); + else + throw new InternalError("Cannot cast declared type!" + variable.toString()); + } else { + Scope blockScope = symbols.getScope(currentScope); + VariableIntermediate tmpVar = blockScope.addVariableIntermediate(); + SymbolType rightType = SymbolTypeInference.inferType(symbols, getRight()); + tmpVar.setTypeInferred(rightType); + StatementAssignment newAssignment = new StatementAssignment(assignment.getlValue(), Operators.getCastUnary(toType), tmpVar.getRef(), assignment.getSource(), Comment.NO_COMMENTS); + assignment.setlValue(tmpVar.getRef()); + stmtIt.add(newAssignment); + } } @Override @@ -173,7 +182,7 @@ public interface ProgramExpressionBinary extends ProgramExpression { Scope blockScope = symbols.getScope(currentScope); VariableIntermediate tmpVar = blockScope.addVariableIntermediate(); SymbolType rightType = SymbolTypeInference.inferType(symbols, getRight()); - tmpVar.setType(rightType); + tmpVar.setTypeInferred(rightType); StatementAssignment newAssignment = new StatementAssignment(assignment.getlValue(), Operators.getCastUnary(toType), tmpVar.getRef(), assignment.getSource(), Comment.NO_COMMENTS); assignment.setlValue(tmpVar.getRef()); stmtIt.add(newAssignment); @@ -314,7 +323,7 @@ public interface ProgramExpressionBinary extends ProgramExpression { public void addLeftCast(SymbolType toType, ListIterator stmtIt, ScopeRef currentScope, ProgramScope symbols) { if(getPointerDereferenceIndexed().getPointer() instanceof ConstantValue) { getPointerDereferenceIndexed().setPointer(new ConstantCastValue(toType, (ConstantValue) getPointerDereferenceIndexed().getPointer())); - } else { + } else { // Try to use CastValue - may later have to be supported! getPointerDereferenceIndexed().setPointer(new CastValue(toType, getPointerDereferenceIndexed().getPointer())); } @@ -324,7 +333,14 @@ public interface ProgramExpressionBinary extends ProgramExpression { public void addRightCast(SymbolType toType, ListIterator stmtIt, ScopeRef currentScope, ProgramScope symbols) { if(getPointerDereferenceIndexed().getIndex() instanceof ConstantValue) { getPointerDereferenceIndexed().setIndex(new ConstantCastValue(toType, (ConstantValue) getPointerDereferenceIndexed().getIndex())); - } else { + } else if( getPointerDereferenceIndexed().getIndex() instanceof VariableRef) { + Variable variable = symbols.getVariable((VariableRef) getPointerDereferenceIndexed().getIndex()); + if(variable.isInferredType()) + variable.setTypeInferred(toType); + else + throw new InternalError("Cannot cast declared type!" + variable.toString()); + + } else { // Try to use CastValue - may later have to be supported! getPointerDereferenceIndexed().setIndex(new CastValue(toType, getPointerDereferenceIndexed().getIndex())); } @@ -360,15 +376,22 @@ public interface ProgramExpressionBinary extends ProgramExpression { @Override public void addLeftCast(SymbolType toType, ListIterator stmtIt, ScopeRef currentScope, ProgramScope symbols) { - throw new InternalError("Not supported!"); + Variable variable = symbols.getVariable(phiVariable.getVariable()); + if(variable.isInferredType()) + variable.setTypeInferred(toType); + else + throw new InternalError("Cannot cast declared type!" + variable.toString()); } @Override public void addRightCast(SymbolType toType, ListIterator stmtIt, ScopeRef currentScope, ProgramScope symbols) { - if(getRight() instanceof ConstantValue) { + if(getRight() instanceof VariableRef) { + Variable variable = symbols.getVariable((VariableRef) getRight()); + if(variable.isInferredType()) + variable.setTypeInferred(toType); + } else if(getRight() instanceof ConstantValue) { value.setrValue(new ConstantCastValue(toType, (ConstantValue) getRight())); - } else { - // Try to use CastValue - may later have to be supported! + } else { value.setrValue(new CastValue(toType, getRight())); } } @@ -380,7 +403,4 @@ public interface ProgramExpressionBinary extends ProgramExpression { } - - - } diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastSNumber.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastSNumber.java new file mode 100644 index 000000000..f63a5c264 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastSNumber.java @@ -0,0 +1,27 @@ +package dk.camelot64.kickc.model.operators; + +import dk.camelot64.kickc.model.CompileError; +import dk.camelot64.kickc.model.symbols.ProgramScope; +import dk.camelot64.kickc.model.types.SymbolType; +import dk.camelot64.kickc.model.values.ConstantInteger; +import dk.camelot64.kickc.model.values.ConstantLiteral; + +/** Unary Cast to signed number operator ( (snumber) x ) */ +public class OperatorCastSNumber extends OperatorCast { + + public OperatorCastSNumber(int precedence) { + super("((snumber))", "_snumber_", precedence, SymbolType.SNUMBER); + } + + @Override + public ConstantLiteral calculateLiteral(ConstantLiteral value, ProgramScope scope) { + if(value instanceof ConstantInteger) + return new ConstantInteger(((ConstantInteger) value).getValue(), SymbolType.SNUMBER); + throw new CompileError("Calculation not implemented " + getOperator() + " " + value ); + } + + @Override + public SymbolType inferType(SymbolType operandType) { + return SymbolType.SNUMBER; + } +} diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastUNumber.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastUNumber.java new file mode 100644 index 000000000..d6ea9e832 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastUNumber.java @@ -0,0 +1,28 @@ +package dk.camelot64.kickc.model.operators; + +import dk.camelot64.kickc.model.CompileError; +import dk.camelot64.kickc.model.symbols.ProgramScope; +import dk.camelot64.kickc.model.types.SymbolType; +import dk.camelot64.kickc.model.values.ConstantInteger; +import dk.camelot64.kickc.model.values.ConstantLiteral; +import dk.camelot64.kickc.model.values.ConstantPointer; + +/** Unary Cast to unsigned number operator ( (unumber) x ) */ +public class OperatorCastUNumber extends OperatorCast { + + public OperatorCastUNumber(int precedence) { + super("((unumber))", "_unumber_", precedence, SymbolType.UNUMBER); + } + + @Override + public ConstantLiteral calculateLiteral(ConstantLiteral value, ProgramScope scope) { + if(value instanceof ConstantInteger) + return new ConstantInteger(((ConstantInteger) value).getValue(), SymbolType.UNUMBER); + throw new CompileError("Calculation not implemented " + getOperator() + " " + value ); + } + + @Override + public SymbolType inferType(SymbolType operandType) { + return SymbolType.UNUMBER; + } +} diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorDivide.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorDivide.java index eb3be39a8..e771d3bb4 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorDivide.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorDivide.java @@ -29,7 +29,7 @@ public class OperatorDivide extends OperatorBinary { @Override public SymbolType inferType(SymbolType left, SymbolType right) { if(left instanceof SymbolTypePointer) { - if(SymbolType.BYTE.equals(right) || SymbolType.WORD.equals(right) || SymbolType.NUMBER.equals(right)) { + if(SymbolType.BYTE.equals(right) || SymbolType.WORD.equals(right) || SymbolType.NUMBER.equals(right)|| SymbolType.UNUMBER.equals(right)|| SymbolType.SNUMBER.equals(right)) { return left; } else { throw new NoMatchingType("Cannot divide pointer by "+right.toString()); diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorGetHigh.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorGetHigh.java index e7ad53157..82367f396 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorGetHigh.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorGetHigh.java @@ -50,6 +50,10 @@ public class OperatorGetHigh extends OperatorUnary { return SymbolType.BYTE; } else if(SymbolType.NUMBER.equals(operandType)) { return SymbolType.NUMBER; + } else if(SymbolType.UNUMBER.equals(operandType)) { + return SymbolType.UNUMBER; + } else if(SymbolType.SNUMBER.equals(operandType)) { + return SymbolType.UNUMBER; } throw new CompileError("Type inference not implemented "+getOperator()+" "+operandType); } diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorGetLow.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorGetLow.java index 6d8e03c03..e162f4d0d 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorGetLow.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorGetLow.java @@ -50,6 +50,10 @@ public class OperatorGetLow extends OperatorUnary { return SymbolType.BYTE; } else if(SymbolType.NUMBER.equals(operandType)) { return SymbolType.NUMBER; + } else if(SymbolType.UNUMBER.equals(operandType)) { + return SymbolType.UNUMBER; + } else if(SymbolType.SNUMBER.equals(operandType)) { + return SymbolType.UNUMBER; } throw new CompileError("Type inference not implemented "+getOperator()+" "+operandType); } diff --git a/src/main/java/dk/camelot64/kickc/model/operators/Operators.java b/src/main/java/dk/camelot64/kickc/model/operators/Operators.java index 173ab0e8c..0afad2224 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/Operators.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/Operators.java @@ -26,6 +26,8 @@ public class Operators { public static final OperatorUnary CAST_DWORD = new OperatorCastDWord(2); public static final OperatorUnary CAST_SDWORD = new OperatorCastSDWord(2); public static final OperatorUnary CAST_BOOL= new OperatorCastBool(2); + public static final OperatorUnary CAST_UNUMBER = new OperatorCastUNumber(2); + public static final OperatorUnary CAST_SNUMBER = new OperatorCastSNumber(2); public static final OperatorUnary SIZEOF = new OperatorSizeOf(2); public static final OperatorUnary TYPEID = new OperatorTypeId(2); public static final OperatorBinary MULTIPLY = new OperatorMultiply(3); @@ -149,6 +151,10 @@ public class Operators { return CAST_DWORD; } else if(SymbolType.SDWORD.equals(castType)) { return CAST_SDWORD; + } else if(SymbolType.UNUMBER.equals(castType)) { + return CAST_UNUMBER; + } else if(SymbolType.SNUMBER.equals(castType)) { + return CAST_SNUMBER; } else if(SymbolType.BOOLEAN.equals(castType)) { return CAST_BOOL; } else if(castType instanceof SymbolTypePointer) { diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/VariableVersion.java b/src/main/java/dk/camelot64/kickc/model/symbols/VariableVersion.java index 7aca0fd3a..47c67dc0f 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/VariableVersion.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/VariableVersion.java @@ -12,6 +12,7 @@ public class VariableVersion extends Variable { this.setDeclaredAlignment(versionOf.getDeclaredAlignment()); this.setDeclaredRegister(versionOf.getDeclaredRegister()); this.setDeclaredVolatile(versionOf.isDeclaredVolatile()); + this.setInferredType(versionOf.isInferredType()); this.versionOfName = versionOf.getLocalName(); this.setComments(versionOf.getComments()); } diff --git a/src/main/java/dk/camelot64/kickc/model/types/SymbolType.java b/src/main/java/dk/camelot64/kickc/model/types/SymbolType.java index bff9cc686..c0abe5d1b 100644 --- a/src/main/java/dk/camelot64/kickc/model/types/SymbolType.java +++ b/src/main/java/dk/camelot64/kickc/model/types/SymbolType.java @@ -117,7 +117,7 @@ public interface SymbolType { * @return true if the type is integer */ static boolean isInteger(SymbolType type) { - return SDWORD.equals(type) || DWORD.equals(type) || SWORD.equals(type) || WORD.equals(type) || SBYTE.equals(type) || BYTE.equals(type) || NUMBER.equals(type); + return SDWORD.equals(type) || DWORD.equals(type) || SWORD.equals(type) || WORD.equals(type) || SBYTE.equals(type) || BYTE.equals(type) || NUMBER.equals(type)|| UNUMBER.equals(type)|| SNUMBER.equals(type); } } diff --git a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java index b2f8c2356..e37c240d9 100644 --- a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java +++ b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java @@ -32,6 +32,16 @@ public class SymbolTypeConversion { if(SymbolType.NUMBER.equals(type1) || SymbolType.NUMBER.equals(type2)) { return SymbolType.NUMBER; } + // If any of the two types are unresolved unsigned - return an unresolved unsigned result + if(SymbolType.UNUMBER.equals(type1) || SymbolType.UNUMBER.equals(type2)) { + return SymbolType.UNUMBER; + } + // If any of the two types are unresolved signed - return an unresolved signed result + if(SymbolType.SNUMBER.equals(type1) || SymbolType.SNUMBER.equals(type2)) { + return SymbolType.SNUMBER; + } + + // Both types are resolved (fixed) integer types SymbolTypeIntegerFixed fixed1 = (SymbolTypeIntegerFixed) type1; SymbolTypeIntegerFixed fixed2 = (SymbolTypeIntegerFixed) type2; // C99 6.3.1.8 a. If two operands have the same type no conversion is performed @@ -82,6 +92,13 @@ public class SymbolTypeConversion { return null; } + // a) If any the two operands are unsigned numbers the result is an unsigned number + if(SymbolType.UNUMBER.equals(leftType) || SymbolType.UNUMBER.equals(rightType)) + return SymbolType.UNUMBER; + // a) If any the two operands are signed numbers the result is an signed number + if(SymbolType.SNUMBER.equals(leftType) || SymbolType.SNUMBER.equals(rightType)) + return SymbolType.SNUMBER; + // Treat pointers like WORD if(leftType instanceof SymbolTypePointer) leftType = SymbolType.WORD; if(rightType instanceof SymbolTypePointer) rightType = SymbolType.WORD; @@ -102,52 +119,70 @@ public class SymbolTypeConversion { return null; } - // Find the cast type if possible - if(numberVal instanceof ConstantValue) { - ConstantLiteral constantLiteral; - try { - constantLiteral = ((ConstantValue) numberVal).calculateLiteral(symbols); - } catch( ConstantNotLiteral e) { - // Postpone til later! - return null; - } - if(constantLiteral instanceof ConstantInteger) { - ConstantInteger constantInteger = (ConstantInteger) constantLiteral; - 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 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; - } else { - // 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) { - smallestUnsignedType = SymbolTypeIntegerFixed.getSmallestUnsigned(-value); - } else { - smallestUnsignedType = SymbolTypeIntegerFixed.getSmallestUnsigned(value); - } - return smallestUnsignedType; - } - } else { - throw new InternalError("Non-number constant has type number " + right.toString(), currentStmt); - } - } + if(fixedType.isSigned()) { + return SymbolType.SNUMBER; } else { - // Postpone til later! - return null; + return SymbolType.UNUMBER; } } + // No number conversion return null; + + } + + + public static SymbolType getSmallestSignedFixedIntegerType(ConstantValue constantValue, ProgramScope symbols) { + ConstantLiteral constantLiteral; + try { + constantLiteral = constantValue.calculateLiteral(symbols); + } catch(ConstantNotLiteral e) { + // Postpone til later! + return null; + } + if(constantLiteral instanceof ConstantInteger) { + Long value = ((ConstantInteger) constantLiteral).getValue(); + // 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 " + constantValue.toString()); + } + return smallestSignedType; + } + // Postpone til later! + return null; } + public static SymbolType getSmallestUnsignedFixedIntegerType(ConstantValue constantValue, ProgramScope symbols) { + ConstantLiteral constantLiteral; + try { + constantLiteral = constantValue.calculateLiteral(symbols); + } catch(ConstantNotLiteral e) { + // Postpone til later! + return null; + } + if(constantLiteral instanceof ConstantInteger) { + Long value = ((ConstantInteger) constantLiteral).getValue(); + // 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 smallestUnsignedType; + if(value < 0) { + smallestUnsignedType = SymbolTypeIntegerFixed.getSmallestUnsigned(-value); + } else { + smallestUnsignedType = SymbolTypeIntegerFixed.getSmallestUnsigned(value); + } + if(smallestUnsignedType == null) { + throw new CompileError("Number constant has value that cannot be represented by a unsigned type " + constantValue.toString()); + } + return smallestUnsignedType; + } + // Postpone til later! + 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 @@ -171,10 +206,26 @@ public class SymbolTypeConversion { // R-value is still a number - constants are probably not done being identified & typed return true; } + if(SymbolType.UNUMBER.equals(rValueType) && SymbolType.isInteger(lValueType)) { + // R-value is still a number - constants are probably not done being identified & typed + return true; + } + if(SymbolType.SNUMBER.equals(rValueType) && SymbolType.isInteger(lValueType)) { + // R-value is still a number - constants are probably not done being identified & typed + return true; + } if(SymbolType.NUMBER.equals(lValueType) && SymbolType.isInteger(rValueType)) { // R-value is still a number - constants are probably not done being identified & typed return true; } + if(SymbolType.UNUMBER.equals(lValueType) && SymbolType.isInteger(rValueType)) { + // R-value is still a number - constants are probably not done being identified & typed + return true; + } + if(SymbolType.SNUMBER.equals(lValueType) && SymbolType.isInteger(rValueType)) { + // R-value is still a number - constants are probably not done being identified & typed + return true; + } if(SymbolType.STRING.equals(rValueType) && lValueType instanceof SymbolTypePointer && SymbolType.BYTE.equals(((SymbolTypePointer) lValueType).getElementType())) { // String value can be assigned into a pointer return true; @@ -189,6 +240,7 @@ public class SymbolTypeConversion { /** * Determines if the left side of an assignment needs a cast to be assigned to the right side + * * @param lValueType The type of the LValue * @param rValueType The type of the RValue * @return true if the left side needs a cast @@ -201,9 +253,8 @@ public class SymbolTypeConversion { else if(lValueType instanceof SymbolTypePointer && SymbolType.STRING.equals(rValueType) && SymbolType.BYTE.equals(((SymbolTypePointer) lValueType).getElementType())) return false; else - return true; + return true; } - } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java b/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java index 9a840e3b4..c4caba00d 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java @@ -64,7 +64,7 @@ public class Pass1PointerSizeofFix extends Pass1Base { VariableRef idx2VarRef = handled.getOrDefault(currentStmt, new LinkedHashMap<>()).get(deref.getIndex()); if(idx2VarRef==null) { VariableIntermediate idx2Var = getScope().getScope(currentBlock.getScope()).addVariableIntermediate(); - idx2Var.setType(SymbolTypeInference.inferType(getScope(), deref.getIndex())); + idx2Var.setTypeInferred(SymbolTypeInference.inferType(getScope(), deref.getIndex())); ConstantRef sizeOfTargetType = OperatorSizeOf.getSizeOfConstantVar(getProgram().getScope(), pointerType.getElementType()); StatementAssignment idx2 = new StatementAssignment(idx2Var.getRef(), deref.getIndex(), Operators.MULTIPLY, sizeOfTargetType, currentStmt.getSource(), Comment.NO_COMMENTS); stmtIt.previous(); @@ -100,7 +100,7 @@ public class Pass1PointerSizeofFix extends Pass1Base { // Adding to a pointer - multiply by sizeof() getLog().append("Fixing pointer addition " + assignment.toString(getProgram(), false)); VariableIntermediate tmpVar = getScope().getScope(block.getScope()).addVariableIntermediate(); - tmpVar.setType(SymbolTypeInference.inferType(getScope(), assignment.getrValue2())); + tmpVar.setTypeInferred(SymbolTypeInference.inferType(getScope(), assignment.getrValue2())); stmtIt.remove(); ConstantRef sizeOfTargetType = OperatorSizeOf.getSizeOfConstantVar(getProgram().getScope(), pointerType.getElementType()); stmtIt.add(new StatementAssignment(tmpVar.getRef(), assignment.getrValue2(), Operators.MULTIPLY, sizeOfTargetType, assignment.getSource(), Comment.NO_COMMENTS)); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java index 76affac0d..58cbc1719 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java @@ -92,6 +92,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { constScope, variableType, constVal); + constantVar.setInferredType(variable.isInferredType()); constantVar.setDeclaredAlignment(variable.getDeclaredAlignment()); constantVar.setDeclaredRegister(variable.getDeclaredRegister()); if(variable.getComments().size() > 0) { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantInlining.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantInlining.java index 4686b3df3..801a63bb4 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantInlining.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantInlining.java @@ -33,8 +33,9 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization { @Override public boolean step() { Map inline = new HashMap<>(); + Map aliasConstants = findAliasConstants(); + inline.putAll(aliasConstants); inline.putAll(findUnnamedConstants()); - inline.putAll(findAliasConstants()); inline.putAll(findConstVarVersions()); // Remove all string constants diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2DeInlineWordDerefIdx.java b/src/main/java/dk/camelot64/kickc/passes/Pass2DeInlineWordDerefIdx.java index 2b0b96cce..267a085ab 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2DeInlineWordDerefIdx.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2DeInlineWordDerefIdx.java @@ -42,7 +42,7 @@ public class Pass2DeInlineWordDerefIdx extends Pass2SsaOptimization { stmtIt.next(); programValue.set(new PointerDereferenceSimple(tmpVar.getRef())); SymbolType pointerType = SymbolTypeInference.inferType(getScope(), new AssignmentRValue(tmpVarAssignment)); - tmpVar.setType(pointerType); + tmpVar.setTypeInferred(pointerType); optimized.set(true); } } diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNAddNumberTypeConversions.java b/src/main/java/dk/camelot64/kickc/passes/PassNAddNumberTypeConversions.java index dcc576213..7f05fe4f3 100644 --- a/src/main/java/dk/camelot64/kickc/passes/PassNAddNumberTypeConversions.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNAddNumberTypeConversions.java @@ -40,6 +40,7 @@ public class PassNAddNumberTypeConversions extends Pass2SsaOptimization { if(SymbolType.NUMBER.equals(rightType)) { getLog().append("Adding number conversion cast (" + castType + ") " + binary.getRight().toString() + " in " + ((currentStmt==null)?"":currentStmt.toString(getProgram(), false))); binary.addRightCast(castType, stmtIt, currentBlock==null?null:currentBlock.getScope(), getScope()); + modified.set(true); } } diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNCastSimplification.java b/src/main/java/dk/camelot64/kickc/passes/PassNCastSimplification.java index 5661a8624..743d7cfe1 100644 --- a/src/main/java/dk/camelot64/kickc/passes/PassNCastSimplification.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNCastSimplification.java @@ -11,10 +11,11 @@ import dk.camelot64.kickc.model.values.RValue; import java.util.concurrent.atomic.AtomicBoolean; -/** Simplifies casts +/** + * Simplifies casts * - Inlines casts of (number) constants * - Removes unnecessary casts - * */ + */ public class PassNCastSimplification extends Pass2SsaOptimization { public PassNCastSimplification(Program program) { @@ -39,12 +40,12 @@ public class PassNCastSimplification extends Pass2SsaOptimization { } else if(unaryOperand instanceof ConstantInteger) { ConstantInteger constantInteger = (ConstantInteger) unaryOperand; if(SymbolType.NUMBER.equals(constantInteger.getType())) { - if(castType instanceof SymbolTypeIntegerFixed ) { + if(castType instanceof SymbolTypeIntegerFixed || SymbolType.UNUMBER.equals(castType) || SymbolType.SNUMBER.equals(castType)) { ConstantInteger newConstInt = new ConstantInteger(constantInteger.getInteger(), castType); programExpression.set(newConstInt); getLog().append("Simplifying constant integer cast " + newConstInt.toString()); optimized.set(true); - } else if(castType instanceof SymbolTypePointer) { + } else if(castType instanceof SymbolTypePointer) { ConstantPointer newConstPointer = new ConstantPointer(constantInteger.getInteger(), ((SymbolTypePointer) castType).getElementType()); programExpression.set(newConstPointer); getLog().append("Simplifying constant pointer cast " + newConstPointer.toString()); diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNFinalizeNumberTypeConversions.java b/src/main/java/dk/camelot64/kickc/passes/PassNFinalizeNumberTypeConversions.java new file mode 100644 index 000000000..76b2b33a3 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/passes/PassNFinalizeNumberTypeConversions.java @@ -0,0 +1,65 @@ +package dk.camelot64.kickc.passes; + +import dk.camelot64.kickc.model.InternalError; +import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.iterator.ProgramValueIterator; +import dk.camelot64.kickc.model.symbols.ConstantVar; +import dk.camelot64.kickc.model.types.SymbolType; +import dk.camelot64.kickc.model.types.SymbolTypeConversion; +import dk.camelot64.kickc.model.values.*; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Finalize any constant integers to the smallest fixed size signed/unsigned type - if they have been resolved as snumber/unumber. + */ +public class PassNFinalizeNumberTypeConversions extends Pass2SsaOptimization { + + public PassNFinalizeNumberTypeConversions(Program program) { + super(program); + } + + @Override + public boolean step() { + AtomicBoolean modified = new AtomicBoolean(false); + ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> { + if(programValue.get() instanceof ConstantInteger) { + ConstantInteger constantInteger = (ConstantInteger) programValue.get(); + if(SymbolType.UNUMBER.equals(constantInteger.getType())) { + SymbolType integerType = SymbolTypeConversion.getSmallestUnsignedFixedIntegerType(constantInteger, getScope()); + programValue.set(new ConstantInteger(constantInteger.getValue(), integerType)); + getLog().append("Finalized unsigned number type "+programValue.get().toString(getProgram())); + modified.set(true); + } else if(SymbolType.SNUMBER.equals(constantInteger.getType())) { + SymbolType integerType = SymbolTypeConversion.getSmallestSignedFixedIntegerType(constantInteger, getScope()); + programValue.set(new ConstantInteger(constantInteger.getValue(), integerType)); + getLog().append("Finalized signed number type "+programValue.get().toString(getProgram())); + modified.set(true); + } + } else if(programValue.get() instanceof ConstantCastValue) { + ConstantCastValue constantCastValue = (ConstantCastValue) programValue.get(); + SymbolType toType = constantCastValue.getToType(); + if(SymbolType.UNUMBER.equals(toType)) { + if(constantCastValue.getValue() instanceof ConstantRef) { + ConstantRef constRef = (ConstantRef) constantCastValue.getValue(); + ConstantVar constant = getScope().getConstant(constRef); + if(constant.isInferredType()) + constant.setTypeInferred(toType); + else + throw new InternalError("Cannot cast declared type!" + constant.toString()); + } else { + ConstantLiteral constantLiteral = constantCastValue.getValue().calculateLiteral(getProgram().getScope()); + SymbolType smallestUnsigned = SymbolTypeConversion.getSmallestUnsignedFixedIntegerType(constantLiteral, getScope()); + if(smallestUnsigned!=null) { + constantCastValue.setToType(smallestUnsigned); + } + } + } + if(SymbolType.SNUMBER.equals(toType)) + throw new InternalError("TODO: Finalize ConstantCast"); + } + }); + return modified.get(); + } + +} diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNTypeInference.java b/src/main/java/dk/camelot64/kickc/passes/PassNTypeInference.java index 4e135e916..39c586a4e 100644 --- a/src/main/java/dk/camelot64/kickc/passes/PassNTypeInference.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNTypeInference.java @@ -60,7 +60,7 @@ public class PassNTypeInference extends Pass2SsaOptimization { LValue lValue = call.getlValue(); if(lValue instanceof VariableRef) { Variable symbol = programScope.getVariable((VariableRef) lValue); - if(SymbolType.VAR.equals(symbol.getType()) || SymbolType.NUMBER.equals(symbol.getType())) { + if(SymbolType.VAR.equals(symbol.getType()) || SymbolType.NUMBER.equals(symbol.getType())|| SymbolType.UNUMBER.equals(symbol.getType())|| SymbolType.SNUMBER.equals(symbol.getType())) { Procedure procedure = programScope.getProcedure(call.getProcedure()); SymbolType type = procedure.getReturnType(); setInferedType(program, call, symbol, type); @@ -73,7 +73,7 @@ public class PassNTypeInference extends Pass2SsaOptimization { LValue lValue = call.getlValue(); if(lValue instanceof VariableRef) { Variable symbol = programScope.getVariable((VariableRef) lValue); - if(SymbolType.VAR.equals(symbol.getType()) || SymbolType.NUMBER.equals(symbol.getType())) { + if(SymbolType.VAR.equals(symbol.getType()) || SymbolType.NUMBER.equals(symbol.getType())|| SymbolType.UNUMBER.equals(symbol.getType())|| SymbolType.SNUMBER.equals(symbol.getType())) { SymbolType procedureType = SymbolTypeInference.inferType(programScope, call.getProcedure()); if(procedureType instanceof SymbolTypeProcedure) { SymbolType returnType = ((SymbolTypeProcedure) procedureType).getReturnType(); @@ -86,7 +86,7 @@ public class PassNTypeInference extends Pass2SsaOptimization { private static void updateInferedTypePhiVariable(Program program, StatementPhiBlock.PhiVariable phiVariable) { ProgramScope programScope = program.getScope(); Variable symbol = programScope.getVariable(phiVariable.getVariable()); - if(SymbolType.VAR.equals(symbol.getType()) || SymbolType.NUMBER.equals(symbol.getType())) { + if(SymbolType.VAR.equals(symbol.getType()) || SymbolType.NUMBER.equals(symbol.getType())|| SymbolType.UNUMBER.equals(symbol.getType())|| SymbolType.SNUMBER.equals(symbol.getType())) { SymbolType type = null; for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) { RValue rValue = phiRValue.getrValue(); @@ -112,7 +112,7 @@ public class PassNTypeInference extends Pass2SsaOptimization { LValue lValue = assignment.getlValue(); if(lValue instanceof VariableRef) { Variable symbol = programScope.getVariable((VariableRef) lValue); - if(SymbolType.VAR.equals(symbol.getType()) || SymbolType.NUMBER.equals(symbol.getType())) { + if(SymbolType.VAR.equals(symbol.getType()) || SymbolType.NUMBER.equals(symbol.getType())|| SymbolType.UNUMBER.equals(symbol.getType()) || SymbolType.SNUMBER.equals(symbol.getType())) { SymbolType type = SymbolTypeInference.inferType(programScope, new AssignmentRValue(assignment)); setInferedType(program, assignment, symbol, type); // If the type is an array or a string the symbol is constant diff --git a/src/test/kc/sandbox.kc b/src/test/kc/sandbox.kc index 3ff3ae112..d84bb18f5 100644 --- a/src/test/kc/sandbox.kc +++ b/src/test/kc/sandbox.kc @@ -48,10 +48,10 @@ byte myprintf(byte *dst, byte *str, word w1, word w2, word w3) { if (bTrailing != 0 && bDigits > b) for (; bDigits > b; --bDigits) dst[bLen++] = ' '; } else if (b == 'x' || b == 'X'){ // hex b = ((byte)w >> 4) & 0xF; - dst[bLen++] = (b < 10 ? '0' : 0x57ub) + b; + dst[bLen++] = (b < 10 ? '0' : 0x57) + b; // "('a' - 10)" is the normal way -- not supported -- https://gitlab.com/camelot/kickc/issues/184 [FIXED] // (b < 10 ? '0' : 0x57) not supported - b = (byte)w & 0xF; dst[bLen++] = (b < 10 ? '0' : 0x57ub) + b; + b = (byte)w & 0xF; dst[bLen++] = (b < 10 ? '0' : 0x57) + b; } bFormat = 0; continue; diff --git a/src/test/kc/ternary-inference.kc b/src/test/kc/ternary-inference.kc index 4f6e29973..30b892c79 100644 --- a/src/test/kc/ternary-inference.kc +++ b/src/test/kc/ternary-inference.kc @@ -3,6 +3,6 @@ void main() { const byte* screen = 0x400; for(byte i: 0..10) { - screen[i] = (i<5?0x57ub:'0')+i; + screen[i] = (i<5?0x57:'0')+i; } } \ No newline at end of file