diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index b09fbec23..3545acae7 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -277,7 +277,6 @@ public class Compiler { List optimizations = new ArrayList<>(); optimizations.add(new Pass2FixInlineConstructors(program)); optimizations.add(new PassNAddNumberTypeConversions(program)); - optimizations.add(new PassNAddInitializerValueListTypeCasts(program)); optimizations.add(new Pass2InlineCast(program)); optimizations.add(new PassNCastSimplification(program)); optimizations.add(new PassNFinalizeNumberTypeConversions(program)); @@ -302,7 +301,6 @@ public class Compiler { optimizations.add(new PassNArrayElementAddressOfRewriting(program)); optimizations.add(new Pass2ConditionalJumpSequenceImprovement(program)); optimizations.add(new Pass2ConstantRValueConsolidation(program)); - optimizations.add(new Pass2ConstantInitializerValueLists(program)); optimizations.add(new Pass2ConstantIdentification(program)); optimizations.add(new Pass2ConstantValues(program)); optimizations.add(new Pass2ConstantCallPointerIdentification(program)); diff --git a/src/main/java/dk/camelot64/kickc/model/ConstantValueLists.java b/src/main/java/dk/camelot64/kickc/model/ConstantValueLists.java new file mode 100644 index 000000000..2a2ea86eb --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/model/ConstantValueLists.java @@ -0,0 +1,160 @@ +package dk.camelot64.kickc.model; + +import dk.camelot64.kickc.model.iterator.ProgramValue; +import dk.camelot64.kickc.model.statements.StatementSource; +import dk.camelot64.kickc.model.symbols.StructDefinition; +import dk.camelot64.kickc.model.symbols.Variable; +import dk.camelot64.kickc.model.types.*; +import dk.camelot64.kickc.model.values.*; + +import java.util.*; + +/** Utility methods for finding constant struct/array values from {@link dk.camelot64.kickc.model.values.ValueList}. */ +public class ConstantValueLists { + + /** + * Add cast to a value inside a value list initializer based on the declared type of the symbol. + * + * @param declaredType The declared type of the value + * @param isArray true if the declared variable is an array + * @param programValue The value wrapped in a program value + * @param source The current statement + * @return true if anything was modified + */ + public static boolean addValueCasts(SymbolType declaredType, boolean isArray, ProgramValue programValue, Program program, StatementSource source) { + boolean exprModified = false; + Value value = programValue.get(); + if(value instanceof ValueList) { + ValueList valueList = (ValueList) value; + if(declaredType instanceof SymbolTypePointer && isArray) { + SymbolTypePointer declaredArrayType = (SymbolTypePointer) declaredType; + // Recursively cast all sub-elements + SymbolType declaredElmType = declaredArrayType.getElementType(); + int size = valueList.getList().size(); + // TODO: Check declared array size vs. actual size + for(int i = 0; i < size; i++) { + exprModified |= addValueCasts(declaredElmType, false, new ProgramValue.ProgramValueListElement(valueList, i), program, source); + } + // Add a cast to the value list itself + programValue.set(new CastValue(declaredType, valueList)); + } else if(declaredType instanceof SymbolTypeStruct) { + SymbolTypeStruct declaredStructType = (SymbolTypeStruct) declaredType; + // Recursively cast all sub-elements + StructDefinition structDefinition = declaredStructType.getStructDefinition(program.getScope()); + Collection memberDefinitions = structDefinition.getAllVars(false); + int size = memberDefinitions.size(); + if(size != valueList.getList().size()) { + throw new CompileError( + "Struct initializer has wrong size (" + valueList.getList().size() + "), " + + "which does not match the number of members in " + declaredStructType.getTypeName() + " (" + size + " members).\n" + + " Struct initializer: " + valueList.toString(program), + source); + } + Iterator memberDefIt = memberDefinitions.iterator(); + for(int i = 0; i < size; i++) { + Variable memberDef = memberDefIt.next(); + exprModified |= addValueCasts(memberDef.getType(), memberDef.isArray(), new ProgramValue.ProgramValueListElement(valueList, i), program, source); + } + // Add a cast to the value list itself + programValue.set(new CastValue(declaredType, valueList)); + } else { + // TODO: Handle word/dword initializers + throw new InternalError("Type not handled! " + declaredType); + } + } else { + SymbolType valueType = SymbolTypeInference.inferType(program.getScope(), (RValue) value); + if(SymbolType.NUMBER.equals(valueType) || SymbolType.VAR.equals(valueType)) { + // Check if the value fits. + if(!SymbolTypeConversion.assignmentTypeMatch(declaredType, valueType)) { + throw new CompileError("Declared type " + declaredType + " does not match element type " + valueType, source); + } + // TODO: Test if the value matches the declared type! + // Add a cast to the value + if(value instanceof ConstantValue) { + programValue.set(new ConstantCastValue(declaredType, (ConstantValue) value)); + } else { + programValue.set(new CastValue(declaredType, (RValue) value)); + } + exprModified = true; + } + } + return exprModified; + } + + /** + * Convert a value list (with casts) to a constant value of the declared type - if all sub-values are constant. Otherwise returns null. + * + * @param declaredType The type of the lvalue + * @param valueList The list of values + * @return The constant value if all list elements are constant. null if elements are not constant + */ + public static ConstantValue getConstantValue(SymbolType declaredType, ValueList valueList, Program program, StatementSource source) { + // Examine whether all list elements are constant + List values = valueList.getList(); + List constantValues = new ArrayList<>(); + for(RValue elmValue : values) { + if(elmValue instanceof ConstantValue) { + ConstantValue constantValue = (ConstantValue) elmValue; + constantValues.add(constantValue); + } else if(elmValue instanceof CastValue) { + // Recursion may be needed + CastValue castValue = (CastValue) elmValue; + if(castValue.getValue() instanceof ValueList) { + ConstantValue constantValue = getConstantValue(castValue.getToType(), (ValueList) castValue.getValue(), program, source); + if(constantValue != null) { + constantValues.add(constantValue); + } else { + // A non-constant was found - exit + return null; + } + } else { + // A non-constant was found - exit + return null; + } + } else { + // A non-constant was found - exit + return null; + } + } + // All elements are constant - convert to constant of declared type + if(declaredType instanceof SymbolTypePointer) { + // Check that type of constant values match the array element type + SymbolType declaredElementType = ((SymbolTypePointer) declaredType).getElementType(); + for(ConstantValue constantValue : constantValues) { + SymbolType elmType = constantValue.getType(program.getScope()); + if(!elmType.equals(declaredElementType)) { + throw new CompileError("Initializer element " + constantValue.toString(program) + " does not match array type " + declaredType.getTypeName(), source); + } + } + // Return the constant array + return new ConstantArrayList(constantValues, declaredElementType); + } else if(declaredType instanceof SymbolTypeStruct) { + // Check that type of constant values match the struct member types + SymbolTypeStruct declaredStructType = (SymbolTypeStruct) declaredType; + StructDefinition structDefinition = declaredStructType.getStructDefinition(program.getScope()); + Collection memberDefs = structDefinition.getAllVars(false); + if(memberDefs.size() != constantValues.size()) { + throw new CompileError( + "Struct initializer has wrong size (" + valueList.getList().size() + "), " + + "which does not match the number of members in " + declaredStructType.getTypeName() + " (\"+size+\" members).\n" + + " Struct initializer: " + valueList.toString(program), + source); + } + Iterator memberDefIt = memberDefs.iterator(); + LinkedHashMap memberValues = new LinkedHashMap<>(); + for(int i = 0; i < constantValues.size(); i++) { + Variable memberDef = memberDefIt.next(); + SymbolType declaredElementType = memberDef.getType(); + ConstantValue memberValue = constantValues.get(i); + SymbolType elmType = memberValue.getType(program.getScope()); + if(!SymbolTypeConversion.assignmentTypeMatch(declaredElementType, elmType)) { + throw new CompileError("Initializer element " + memberValue.toString(program) + " does not match struct member type " + memberDef.toString(program), source); + } + memberValues.put(memberDef.getRef(), memberValue); + } + return new ConstantStructValue(declaredStructType, memberValues); + } else { + throw new InternalError("Not supported " + declaredType); + } + } +} diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java index 458314a9f..22bc7d197 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java @@ -659,12 +659,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor { - if(programValue.get() instanceof CastValue) { - CastValue castValue = (CastValue) programValue.get(); - if(castValue.getValue() instanceof ValueList) { - // Found value list with cast - look through all elements - ConstantValue constantValue = getConstantValueFromList(castValue.getToType(), (ValueList) castValue.getValue(), getProgram(), currentStmt.getSource()); - if(constantValue!=null) { - programValue.set(constantValue); - getLog().append("Identified constant from value list ("+castValue.getToType()+") "+constantValue.toString(getProgram())); - modified[0] = true; - } - } - } - }); - return modified[0]; - } - - /** - * Examine a value list to determine if all elements are constants. - * If they are - convert the value list to a constant value of the declared type - * - * @param declaredType The type of the lvalue - * @param valueList The list of values - * @return The constant value if all list elements are constant. null if elements are not constant - */ - public static ConstantValue getConstantValueFromList(SymbolType declaredType, ValueList valueList, Program program, StatementSource source) { - // Examine whether all list elements are constant - List values = valueList.getList(); - List constantValues = new ArrayList<>(); - for(RValue elmValue : values) { - if(elmValue instanceof ConstantValue) { - ConstantValue constantValue = (ConstantValue) elmValue; - constantValues.add(constantValue); - } else if(elmValue instanceof CastValue) { - // Recursion may be needed - CastValue castValue = (CastValue) elmValue; - if(castValue.getValue() instanceof ValueList) { - ConstantValue constantValue = getConstantValueFromList(castValue.getToType(), (ValueList) castValue.getValue(), program, source); - if(constantValue!=null) { - constantValues.add(constantValue); - } else { - // A non-constant was found - exit - return null; - } - } else { - // A non-constant was found - exit - return null; - } - } else { - // A non-constant was found - exit - return null; - } - } - // All elements are constant - convert to constant of declared type - if(declaredType instanceof SymbolTypePointer) { - // Check that type of constant values match the array element type - SymbolType declaredElementType = ((SymbolTypePointer) declaredType).getElementType(); - for(ConstantValue constantValue : constantValues) { - SymbolType elmType = constantValue.getType(program.getScope()); - if(!elmType.equals(declaredElementType)) { - throw new CompileError("Initializer element "+constantValue.toString(program)+" does not match array type "+declaredType.getTypeName(), source); - } - } - // Return the constant array - return new ConstantArrayList(constantValues, declaredElementType); - } else if(declaredType instanceof SymbolTypeStruct) { - // Check that type of constant values match the struct member types - SymbolTypeStruct declaredStructType = (SymbolTypeStruct) declaredType; - StructDefinition structDefinition = declaredStructType.getStructDefinition(program.getScope()); - Collection memberDefs = structDefinition.getAllVars(false); - if(memberDefs.size()!=constantValues.size()) { - throw new CompileError( - "Struct initializer has wrong size ("+valueList.getList().size()+"), " + - "which does not match the number of members in "+declaredStructType.getTypeName()+" (\"+size+\" members).\n" + - " Struct initializer: "+valueList.toString(program), - source); - } - Iterator memberDefIt = memberDefs.iterator(); - LinkedHashMap memberValues = new LinkedHashMap<>(); - for(int i = 0; i < constantValues.size(); i++) { - Variable memberDef = memberDefIt.next(); - SymbolType declaredElementType = memberDef.getType(); - ConstantValue memberValue = constantValues.get(i); - SymbolType elmType = memberValue.getType(program.getScope()); - if(!SymbolTypeConversion.assignmentTypeMatch(declaredElementType, elmType)) { - throw new CompileError("Initializer element "+ memberValue.toString(program)+" does not match struct member type "+memberDef.toString(program), source); - } - memberValues.put(memberDef.getRef(), memberValue); - } - return new ConstantStructValue(declaredStructType, memberValues); - } else { - throw new InternalError("Not supported "+declaredType); - } - } - -} diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNAddInitializerValueListTypeCasts.java b/src/main/java/dk/camelot64/kickc/passes/PassNAddInitializerValueListTypeCasts.java deleted file mode 100644 index 6b64335db..000000000 --- a/src/main/java/dk/camelot64/kickc/passes/PassNAddInitializerValueListTypeCasts.java +++ /dev/null @@ -1,123 +0,0 @@ -package dk.camelot64.kickc.passes; - -import dk.camelot64.kickc.model.CompileError; -import dk.camelot64.kickc.model.InternalError; -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.iterator.ProgramValue; -import dk.camelot64.kickc.model.operators.Operators; -import dk.camelot64.kickc.model.statements.StatementSource; -import dk.camelot64.kickc.model.symbols.StructDefinition; -import dk.camelot64.kickc.model.symbols.Variable; -import dk.camelot64.kickc.model.types.*; -import dk.camelot64.kickc.model.values.*; - -import java.util.Collection; -import java.util.Iterator; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Add casts to all expressions that are inside value list initializers <{ ... }/code> based on the type of the array/struct - */ -public class PassNAddInitializerValueListTypeCasts extends Pass2SsaOptimization { - - public PassNAddInitializerValueListTypeCasts(Program program) { - super(program); - } - - @Override - public boolean step() { - AtomicBoolean modified = new AtomicBoolean(false); - ProgramExpressionIterator.execute(getProgram(), (binaryExpression, currentStmt, stmtIt, currentBlock) -> { - if(binaryExpression instanceof ProgramExpressionBinary) { - ProgramExpressionBinary binary = (ProgramExpressionBinary) binaryExpression; - if(binary.getRight() instanceof ValueList && binary.getOperator().equals(Operators.ASSIGNMENT)) { - RValue left = binary.getLeft(); - SymbolType declaredType = SymbolTypeInference.inferType(getProgram().getScope(), left); - boolean isArray = false; - if(left instanceof SymbolVariableRef) { - Variable constant = getScope().getVar((SymbolVariableRef) left); - isArray = constant.isArray(); - } - boolean isModified = addValueCasts(declaredType, isArray, binary.getRightValue(), getProgram(), currentStmt.getSource()); - if(isModified) { - getLog().append("Added casts to value list in " + currentStmt.toString(getProgram(), false)); - modified.set(true); - } - } - } - }); - return modified.get(); - } - - /** - * Add cast to a value inside a value list initializer. - * - * @param declaredType The declared type of the value - * @param isArray true if the declared variable is an array - * @param programValue The value wrapped in a program value - * @param source The current statement - * @return true if anything was modified - */ - public static boolean addValueCasts(SymbolType declaredType, boolean isArray, ProgramValue programValue, Program program, StatementSource source) { - boolean exprModified = false; - Value value = programValue.get(); - if(value instanceof ValueList) { - ValueList valueList = (ValueList) value; - if(declaredType instanceof SymbolTypePointer && isArray) { - SymbolTypePointer declaredArrayType = (SymbolTypePointer) declaredType; - // Recursively cast all sub-elements - SymbolType declaredElmType = declaredArrayType.getElementType(); - int size = valueList.getList().size(); - // TODO: Check declared array size vs. actual size - for(int i = 0; i < size; i++) { - exprModified |= addValueCasts(declaredElmType, false, new ProgramValue.ProgramValueListElement(valueList, i), program, source); - } - // Add a cast to the value list itself - programValue.set(new CastValue(declaredType, valueList)); - } else if(declaredType instanceof SymbolTypeStruct) { - SymbolTypeStruct declaredStructType = (SymbolTypeStruct) declaredType; - // Recursively cast all sub-elements - StructDefinition structDefinition = declaredStructType.getStructDefinition(program.getScope()); - Collection memberDefinitions = structDefinition.getAllVars(false); - int size = memberDefinitions.size(); - if(size!=valueList.getList().size()) { - throw new CompileError( - "Struct initializer has wrong size ("+valueList.getList().size()+"), " + - "which does not match the number of members in "+declaredStructType.getTypeName()+" ("+size+" members).\n" + - " Struct initializer: "+valueList.toString(program), - source); - } - Iterator memberDefIt = memberDefinitions.iterator(); - for(int i = 0; i < size; i++) { - Variable memberDef = memberDefIt.next(); - exprModified |= addValueCasts(memberDef.getType(), memberDef.isArray(), new ProgramValue.ProgramValueListElement(valueList, i), program, source); - } - // Add a cast to the value list itself - programValue.set(new CastValue(declaredType, valueList)); - } else { - // TODO: Handle word/dword initializers - throw new InternalError("Type not handled! "+declaredType); - } - } else { - SymbolType valueType = SymbolTypeInference.inferType(program.getScope(), (RValue) value); - if(SymbolType.NUMBER.equals(valueType) || SymbolType.VAR.equals(valueType)) { - // Check if the value fits. - if(!SymbolTypeConversion.assignmentTypeMatch(declaredType, valueType)) { - throw new CompileError("Declared type " + declaredType + " does not match element type " + valueType, source); - } - // TODO: Test if the value matches the declared type! - // Add a cast to the value - if(value instanceof ConstantValue) { - programValue.set(new ConstantCastValue(declaredType, (ConstantValue) value)); - } else { - programValue.set(new CastValue(declaredType, (RValue) value)); - } - exprModified = true; - } - } - return exprModified; - } - -}