From e103a783ce3b18cc831550d3a0a3eb697d4fe2d9 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sun, 22 Dec 2019 18:19:20 +0100 Subject: [PATCH] Working in VariableBuilder for creating variables based on type/scope, directives and configuration. --- ...stantValueLists.java => Initializers.java} | 86 ++++++- .../dk/camelot64/kickc/model/Registers.java | 4 + .../kickc/model/VariableBuilderContext.java | 37 +-- .../Pass0GenerateStatementSequence.java | 216 ++++++------------ .../kickc/passes/Pass1UnwindStructValues.java | 2 +- src/test/ref/struct-11b.sym | 29 +++ 6 files changed, 180 insertions(+), 194 deletions(-) rename src/main/java/dk/camelot64/kickc/model/{ConstantValueLists.java => Initializers.java} (71%) create mode 100644 src/test/ref/struct-11b.sym diff --git a/src/main/java/dk/camelot64/kickc/model/ConstantValueLists.java b/src/main/java/dk/camelot64/kickc/model/Initializers.java similarity index 71% rename from src/main/java/dk/camelot64/kickc/model/ConstantValueLists.java rename to src/main/java/dk/camelot64/kickc/model/Initializers.java index cb56f0487..7e238d244 100644 --- a/src/main/java/dk/camelot64/kickc/model/ConstantValueLists.java +++ b/src/main/java/dk/camelot64/kickc/model/Initializers.java @@ -10,11 +10,84 @@ 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 { +/** Utility methods for initializing variables */ +public class Initializers { /** - * Add cast to a value inside a value list initializer based on the declared type of the symbol. + * Create a statement that initializes a variable with the default (zero) value. The statement has to be added to the program by the caller. + * + * @param type The type of the variable + * @param statementSource The source line + * @return The new statement + */ + public static RValue createZeroValue(SymbolType type, StatementSource statementSource) { + if(type instanceof SymbolTypeIntegerFixed) { + // Add an zero value initializer + return new ConstantInteger(0L, type); + } else if(type instanceof SymbolTypePointer) { + // Add an zero value initializer + SymbolTypePointer typePointer = (SymbolTypePointer) type; + return new ConstantPointer(0L, typePointer.getElementType()); + } else if(type instanceof SymbolTypeStruct) { + // Add an zero-struct initializer + SymbolTypeStruct typeStruct = (SymbolTypeStruct) type; + return new StructZero(typeStruct); + } else { + throw new CompileError("Default initializer not implemented for type " + type.getTypeName(), statementSource); + } + } + + /** + * Get a value for initializing a variable from an expression. + * If possible the value is converted to a ConstantValue. + * + * @param initValue The parsed init expression value (may be null) + * @param type The type of the constant variable (used for creating zero values) + * @param statementSource The statement (used in exceptions. + * @return The constant init-value. Null if the value cannot be turned into a constant init-value. + */ + public static RValue getInitValue(RValue initValue, SymbolType type, boolean isArray, ConstantValue arraySize, Program program, StatementSource statementSource) { + // TODO: Handle struct members + // Create zero-initializers if null + if(initValue == null) { + if(isArray) { + // Add an zero-filled array initializer + SymbolTypePointer typePointer = (SymbolTypePointer) type; + if(arraySize == null) { + throw new CompileError("Error! Array has no declared size. ", statementSource); + } + initValue = new ConstantArrayFilled(typePointer.getElementType(), arraySize); + } else { + // Add an zero-value + initValue = createZeroValue(type, statementSource); + } + } + // Convert initializer value lists to constant if possible + if((initValue instanceof ValueList)) { + ProgramValue programValue = new ProgramValue.GenericValue(initValue); + addValueCasts(type, isArray, programValue, program, statementSource); + 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 = convertToConstant(castValue.getToType(), (ValueList) castValue.getValue(), program, statementSource); + if(constantValue != null) { + // Converted value list to constant!! + initValue = constantValue; + } + } + } + } + // Add pointer cast to integers + if(type instanceof SymbolTypePointer && initValue instanceof ConstantValue && SymbolType.isInteger(((ConstantValue) initValue).getType(program.getScope()))) { + initValue = new ConstantCastValue(type, (ConstantValue) initValue); + } + return initValue; + } + + + /** + * Add casts to a value based on the declared type of the symbol. Recurses to all sub-values. * * @param declaredType The declared type of the value * @param isArray true if the declared variable is an array @@ -22,7 +95,7 @@ public class ConstantValueLists { * @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) { + static boolean addValueCasts(SymbolType declaredType, boolean isArray, ProgramValue programValue, Program program, StatementSource source) { boolean exprModified = false; Value value = programValue.get(); if(value instanceof ValueList) { @@ -103,7 +176,7 @@ public class ConstantValueLists { * @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) { + static ConstantValue convertToConstant(SymbolType declaredType, ValueList valueList, Program program, StatementSource source) { // Examine whether all list elements are constant List values = valueList.getList(); List constantValues = new ArrayList<>(); @@ -115,7 +188,7 @@ public class ConstantValueLists { // Recursion may be needed CastValue castValue = (CastValue) elmValue; if(castValue.getValue() instanceof ValueList) { - ConstantValue constantValue = getConstantValue(castValue.getToType(), (ValueList) castValue.getValue(), program, source); + ConstantValue constantValue = convertToConstant(castValue.getToType(), (ValueList) castValue.getValue(), program, source); if(constantValue != null) { constantValues.add(constantValue); } else { @@ -184,4 +257,5 @@ public class ConstantValueLists { throw new InternalError("Not supported " + declaredType); } } + } diff --git a/src/main/java/dk/camelot64/kickc/model/Registers.java b/src/main/java/dk/camelot64/kickc/model/Registers.java index ee5459e85..273d78734 100644 --- a/src/main/java/dk/camelot64/kickc/model/Registers.java +++ b/src/main/java/dk/camelot64/kickc/model/Registers.java @@ -83,6 +83,10 @@ public class Registers { return variableRef; } + public void setVariableRef(VariableRef variableRef) { + this.variableRef = variableRef; + } + @Override public RegisterType getType() { return RegisterType.MAIN_MEM; diff --git a/src/main/java/dk/camelot64/kickc/model/VariableBuilderContext.java b/src/main/java/dk/camelot64/kickc/model/VariableBuilderContext.java index 90747abfc..186170bd2 100644 --- a/src/main/java/dk/camelot64/kickc/model/VariableBuilderContext.java +++ b/src/main/java/dk/camelot64/kickc/model/VariableBuilderContext.java @@ -1,11 +1,7 @@ package dk.camelot64.kickc.model; import dk.camelot64.kickc.model.statements.StatementSource; -import dk.camelot64.kickc.model.symbols.*; -import dk.camelot64.kickc.model.types.SymbolType; -import dk.camelot64.kickc.model.types.SymbolTypePointer; -import dk.camelot64.kickc.model.types.SymbolTypeStruct; -import dk.camelot64.kickc.model.values.ScopeRef; +import dk.camelot64.kickc.model.symbols.Variable; import dk.camelot64.kickc.model.values.VariableRef; import java.util.List; @@ -18,37 +14,6 @@ public class VariableBuilderContext { public VariableBuilderContext() { } - /** - * Find the variable kind for a declared variable (not used for intermediates or PHI-versions) - * - * @param type The type of the variable - * @param scope The scope - * @param isParameter true if the variable is a procedure parameter - * @param sourceDirectives The directives in the source code - * @param source The source line (for exceptions) - * @return The variable kind - */ - public Variable.Kind getKind(SymbolType type, Scope scope, boolean isParameter, boolean isArray, List sourceDirectives, StatementSource source) { - // Look for const without volatile - if(hasDirective(Directive.Const.class, sourceDirectives)) - if(!hasDirective(Directive.Volatile.class, sourceDirectives)) - return Variable.Kind.CONSTANT; - // Look for array (which is implicitly const - if(isArray) - return Variable.Kind.CONSTANT; - // It is not a constant - determine PHI_MASTER vs LOAD_STORE - if(hasDirective(Directive.FormSsa.class, sourceDirectives)) - return Variable.Kind.PHI_MASTER; - if(hasDirective(Directive.FormMa.class, sourceDirectives)) - return Variable.Kind.LOAD_STORE; - if(hasDirective(Directive.Register.class, sourceDirectives)) - return Variable.Kind.PHI_MASTER; - if(hasDirective(Directive.NamedRegister.class, sourceDirectives)) - return Variable.Kind.PHI_MASTER; - // TODO: Add strategy for selecting LOAD_STORE for global vars - return Variable.Kind.PHI_MASTER; - } - /** * Applies directives to a variable. * diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java index 3c4dca6bd..3cf7eaead 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java @@ -3,13 +3,13 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.NumberParser; import dk.camelot64.kickc.SourceLoader; import dk.camelot64.kickc.asm.AsmClobber; -import dk.camelot64.kickc.model.InternalError; import dk.camelot64.kickc.model.*; -import dk.camelot64.kickc.model.iterator.ProgramValue; import dk.camelot64.kickc.model.operators.*; import dk.camelot64.kickc.model.statements.*; import dk.camelot64.kickc.model.symbols.*; -import dk.camelot64.kickc.model.types.*; +import dk.camelot64.kickc.model.types.SymbolType; +import dk.camelot64.kickc.model.types.SymbolTypePointer; +import dk.camelot64.kickc.model.types.SymbolTypeProcedure; import dk.camelot64.kickc.model.values.*; import dk.camelot64.kickc.parser.CParser; import dk.camelot64.kickc.parser.KickCParser; @@ -565,77 +565,69 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor