diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmEncodingHelper.java b/src/main/java/dk/camelot64/kickc/fragment/AsmEncodingHelper.java new file mode 100644 index 000000000..c5e5e1dfa --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmEncodingHelper.java @@ -0,0 +1,70 @@ +package dk.camelot64.kickc.fragment; + +import dk.camelot64.kickc.asm.AsmProgram; +import dk.camelot64.kickc.model.ControlFlowBlock; +import dk.camelot64.kickc.model.iterator.ProgramValue; +import dk.camelot64.kickc.model.iterator.ProgramValueHandler; +import dk.camelot64.kickc.model.iterator.ProgramValueIterator; +import dk.camelot64.kickc.model.statements.Statement; +import dk.camelot64.kickc.model.values.ConstantChar; +import dk.camelot64.kickc.model.values.ConstantString; +import dk.camelot64.kickc.model.values.StringEncoding; +import dk.camelot64.kickc.model.values.Value; + +import java.util.LinkedHashSet; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; + +public class AsmEncodingHelper { + + /** + * Ensure that the current encoding in the ASM matches any encoding in the data to be emitted + * + * @param asm The ASM program (where any .encoding directive will be emitted) + * @param asmFragmentInstance The ASM fragment to be emitted + */ + static void ensureEncoding(AsmProgram asm, AsmFragmentInstanceSpec asmFragmentInstance) { + asm.ensureEncoding(getEncoding(asmFragmentInstance)); + } + + public static void ensureEncoding(AsmProgram asm, Value value) { + asm.ensureEncoding(getEncoding(value)); + } + + /** + * Examine a constantvalue to see if any string encoding information is present + * + * @param value The constant to examine + * @return Any encoding found inside the constant + */ + public static Set getEncoding(Value value) { + LinkedHashSet encodings = new LinkedHashSet<>(); + ProgramValue programValue = new ProgramValue.GenericValue(value); + ProgramValueHandler handler = (ProgramValue pVal, Statement currentStmt, ListIterator stmtIt, ControlFlowBlock currentBlock) -> { + Value val = pVal.get(); + if(val instanceof ConstantChar) { + encodings.add(((ConstantChar) val).getEncoding()); + } else if(val instanceof ConstantString) { + encodings.add(((ConstantString) val).getEncoding()); + } + }; + ProgramValueIterator.execute(programValue, handler, null, null, null); + return encodings; + } + + /** + * Examine an ASM fragment to see if any string encoding information is present + * + * @param asmFragmentInstance The asm fragment instance to examine + * @return Any encoding found inside the constant + */ + private static Set getEncoding(AsmFragmentInstanceSpec asmFragmentInstance) { + LinkedHashSet encodings = new LinkedHashSet<>(); + Map bindings = asmFragmentInstance.getBindings(); + for(Value boundValue : bindings.values()) { + encodings.addAll(getEncoding(boundValue)); + } + return encodings; + } +} diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentCodeGenerator.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentCodeGenerator.java new file mode 100644 index 000000000..62edc75ae --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentCodeGenerator.java @@ -0,0 +1,43 @@ +package dk.camelot64.kickc.fragment; + +import dk.camelot64.kickc.asm.AsmProgram; +import dk.camelot64.kickc.model.Program; + +public class AsmFragmentCodeGenerator { + + /** + * Generate ASM code for an ASM fragment instance + * + * @param asm The ASM program to generate into + * @param fragmentInstanceSpec The ASM fragment instance specification + * @param program The program. Used for getting global statics. + */ + public static void generateAsm(AsmProgram asm, AsmFragmentInstanceSpec fragmentInstanceSpec, Program program) { + AsmEncodingHelper.ensureEncoding(asm, fragmentInstanceSpec); + String initialSignature = fragmentInstanceSpec.getSignature(); + AsmFragmentInstance fragmentInstance = null; + StringBuilder fragmentVariationsTried = new StringBuilder(); + while(fragmentInstance == null) { + try { + final AsmFragmentTemplateSynthesizer cpuSynthesizer = program.getAsmFragmentMasterSynthesizer().getSynthesizer(program.getTargetCpu()); + fragmentInstance = cpuSynthesizer.getFragmentInstance(fragmentInstanceSpec, program.getLog()); + } catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) { + // Unknown fragment - keep looking through alternative ASM fragment instance specs until we have tried them all + String signature = fragmentInstanceSpec.getSignature(); + fragmentVariationsTried.append(signature).append(" "); + if(fragmentInstanceSpec.hasNextVariation()) { + fragmentInstanceSpec.nextVariation(); + if(program.getLog().isVerboseFragmentLog()) { + program.getLog().append("Fragment not found " + signature + ". Attempting another variation " + fragmentInstanceSpec.getSignature()); + } + } else { + // No more variations available - fail with an error + throw new AsmFragmentTemplateSynthesizer.UnknownFragmentException("Fragment not found " + initialSignature + ". Attempted variations " + fragmentVariationsTried); + } + } + } + asm.getCurrentChunk().setFragment(fragmentInstance.getFragmentName()); + fragmentInstance.generate(asm); + } + +} diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java index 00fa06cc5..6feddb330 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java @@ -83,7 +83,7 @@ public class AsmFragmentInstanceSpec { /** * Does any more variations of the ASM fragment instance specification exist? * Variations are used for finding the right fragment to use for constant numbers. - * For instance the number 1000 can be represented as several different types (unsigned/signed word/dword). + * For instance the number 1000 can be represented as several types (unsigned/signed word/dword). * * @return true if more variations exits */ diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index a2144cfde..7f091cf31 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -6,9 +6,6 @@ import dk.camelot64.kickc.asm.*; import dk.camelot64.kickc.fragment.*; import dk.camelot64.kickc.model.InternalError; import dk.camelot64.kickc.model.*; -import dk.camelot64.kickc.model.iterator.ProgramValue; -import dk.camelot64.kickc.model.iterator.ProgramValueHandler; -import dk.camelot64.kickc.model.iterator.ProgramValueIterator; import dk.camelot64.kickc.model.operators.Operators; import dk.camelot64.kickc.model.statements.*; import dk.camelot64.kickc.model.symbols.*; @@ -461,7 +458,7 @@ public class Pass4CodeGeneration { // Add any comments generateComments(asm, constantVar.getComments()); // Ensure encoding is good - ensureEncoding(asm, constantVar.getInitValue()); + AsmEncodingHelper.ensureEncoding(asm, constantVar.getInitValue()); asm.addConstant(AsmFormat.asmFix(asmName), asmConstant); } @@ -469,7 +466,7 @@ public class Pass4CodeGeneration { // Add any comments generateComments(asm, variable.getComments()); // Ensure encoding is good - ensureEncoding(asm, variable.getInitValue()); + AsmEncodingHelper.ensureEncoding(asm, variable.getInitValue()); // Find the constant value calculation asm.addLabelDecl(AsmFormat.asmFix(asmName), asmConstant); } @@ -666,7 +663,7 @@ public class Pass4CodeGeneration { ConstantValue paddingSizeVal = new ConstantInteger(paddingSize); String paddingBytesAsm = AsmFormat.getAsmConstant(program, paddingSizeVal, 99, scopeRef); ConstantValue zeroValue = new ConstantInteger(0l, SymbolType.BYTE); - dataChunk.addDataZeroFilled(AsmDataNumeric.Type.BYTE, paddingBytesAsm, (int) paddingSize, getEncoding(zeroValue)); + dataChunk.addDataZeroFilled(AsmDataNumeric.Type.BYTE, paddingBytesAsm, (int) paddingSize, AsmEncodingHelper.getEncoding(zeroValue)); } } else if(value instanceof StructZero) { final SymbolTypeStruct typeStruct = ((StructZero) value).getTypeStruct(); @@ -713,12 +710,12 @@ public class Pass4CodeGeneration { if(declaredSize != null) { bytes = declaredSize * elementType.getSizeBytes(); } - dataChunk.addDataKickAsm(bytes, kickAsm.getKickAsmCode(), getEncoding(value)); + dataChunk.addDataKickAsm(bytes, kickAsm.getKickAsmCode(), AsmEncodingHelper.getEncoding(value)); dataNumElements = bytes; } else if(value instanceof ConstantString) { ConstantString stringValue = (ConstantString) value; String asmConstant = AsmFormat.getAsmConstant(program, stringValue, 99, scopeRef); - dataChunk.addDataString(asmConstant, getEncoding(stringValue)); + dataChunk.addDataString(asmConstant, AsmEncodingHelper.getEncoding(stringValue)); if(stringValue.isZeroTerminated()) { dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, "0", null); } @@ -748,7 +745,7 @@ public class Pass4CodeGeneration { } ConstantValue zeroValue = Initializers.createZeroValue(new Initializers.ValueTypeSpec(elementType), null); if(zeroValue instanceof ConstantInteger | zeroValue instanceof ConstantPointer) { - dataChunk.addDataZeroFilled(getNumericType(elementType), paddingBytesAsm, (int) paddingSize, getEncoding(zeroValue)); + dataChunk.addDataZeroFilled(getNumericType(elementType), paddingBytesAsm, (int) paddingSize, AsmEncodingHelper.getEncoding(zeroValue)); } else { for(int i = 0; i < paddingSize; i++) { addChunkData(dataChunk, zeroValue, elementType, null, scopeRef); @@ -760,20 +757,20 @@ public class Pass4CodeGeneration { ConstantString stringValue = (ConstantString) value; // Ensure encoding is good String asmConstant = AsmFormat.getAsmConstant(program, stringValue, 99, scopeRef); - dataChunk.addDataString(asmConstant, getEncoding(stringValue)); + dataChunk.addDataString(asmConstant, AsmEncodingHelper.getEncoding(stringValue)); if(stringValue.isZeroTerminated()) { dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, "0", null); } } else if(SymbolType.BYTE.equals(valueType) || SymbolType.SBYTE.equals(valueType)) { - dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value)); + dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, AsmFormat.getAsmConstant(program, value, 99, scopeRef), AsmEncodingHelper.getEncoding(value)); } else if(SymbolType.WORD.equals(valueType) || SymbolType.SWORD.equals(valueType)) { - dataChunk.addDataNumeric(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value)); + dataChunk.addDataNumeric(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), AsmEncodingHelper.getEncoding(value)); } else if(SymbolType.DWORD.equals(valueType) || SymbolType.SDWORD.equals(valueType)) { - dataChunk.addDataNumeric(AsmDataNumeric.Type.DWORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value)); + dataChunk.addDataNumeric(AsmDataNumeric.Type.DWORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), AsmEncodingHelper.getEncoding(value)); } else if(valueType instanceof SymbolTypePointer) { - dataChunk.addDataNumeric(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value)); + dataChunk.addDataNumeric(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), AsmEncodingHelper.getEncoding(value)); } else if(SymbolType.BOOLEAN.equals(valueType)) { - dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value)); + dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, AsmFormat.getAsmConstant(program, value, 99, scopeRef), AsmEncodingHelper.getEncoding(value)); } else { throw new InternalError("Unhandled array element type " + valueType.toString() + " value " + value.toString(program)); } @@ -848,7 +845,7 @@ public class Pass4CodeGeneration { throw new AsmFragmentInstance.AluNotApplicableException(); } StatementAssignment assignment = (StatementAssignment) statement; - generateAsm(asm, AsmFragmentInstanceSpecBuilder.assignmentAlu(assignment, assignmentAlu, program)); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.assignmentAlu(assignment, assignmentAlu, program), program); aluState.clear(); return; } @@ -871,17 +868,17 @@ public class Pass4CodeGeneration { if(assignment.getOperator() == null && assignment.getrValue1() == null && isRegisterCopy(lValue, assignment.getrValue2())) { //asm.addComment(lValue.toString(program) + " = " + assignment.getrValue2().toString(program) + " // register copy " + getRegister(lValue)); } else { - generateAsm(asm, AsmFragmentInstanceSpecBuilder.assignment(assignment, program)); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.assignment(assignment, program), program); } } } else if(statement instanceof StatementConditionalJump) { - generateAsm(asm, AsmFragmentInstanceSpecBuilder.conditionalJump((StatementConditionalJump) statement, block, program)); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.conditionalJump((StatementConditionalJump) statement, block, program), program); } else if(statement instanceof StatementCall) { StatementCall call = (StatementCall) statement; Procedure procedure = getScope().getProcedure(call.getProcedure()); if(procedure.isDeclaredIntrinsic()) { if(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4.equals(procedure.getFullName())) { - generateAsm(asm, AsmFragmentInstanceSpecBuilder.makelong4(call, program)); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.makelong4(call, program), program); } else { throw new CompileError("Intrinsic procedure not supported " + procedure.toString(program)); } @@ -905,12 +902,12 @@ public class Pass4CodeGeneration { StatementCallExecute call = (StatementCallExecute) statement; RValue procedureRVal = call.getProcedureRVal(); // Generate ASM for a call - generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program)); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); if(!(procedureRVal instanceof ProcedureRef)) { asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL); } } else if(statement instanceof StatementExprSideEffect) { - generateAsm(asm, AsmFragmentInstanceSpecBuilder.exprSideEffect((StatementExprSideEffect) statement, program)); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.exprSideEffect((StatementExprSideEffect) statement, program), program); } else if(statement instanceof StatementReturn) { Procedure procedure = null; ScopeRef scope = block.getScope(); @@ -953,40 +950,6 @@ public class Pass4CodeGeneration { } } - /** - * Generate ASM code for an ASM fragment instance - * - * @param asm The ASM program to generate into - * @param fragmentInstanceSpec The ASM fragment instance specification - */ - private void generateAsm(AsmProgram asm, AsmFragmentInstanceSpec fragmentInstanceSpec) { - ensureEncoding(asm, fragmentInstanceSpec); - String initialSignature = fragmentInstanceSpec.getSignature(); - AsmFragmentInstance fragmentInstance = null; - StringBuilder fragmentVariationsTried = new StringBuilder(); - while(fragmentInstance == null) { - try { - final AsmFragmentTemplateSynthesizer cpuSynthesizer = program.getAsmFragmentMasterSynthesizer().getSynthesizer(program.getTargetCpu()); - fragmentInstance = cpuSynthesizer.getFragmentInstance(fragmentInstanceSpec, program.getLog()); - } catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) { - // Unknown fragment - keep looking through alternative ASM fragment instance specs until we have tried them all - String signature = fragmentInstanceSpec.getSignature(); - fragmentVariationsTried.append(signature).append(" "); - if(fragmentInstanceSpec.hasNextVariation()) { - fragmentInstanceSpec.nextVariation(); - if(program.getLog().isVerboseFragmentLog()) { - program.getLog().append("Fragment not found " + signature + ". Attempting another variation " + fragmentInstanceSpec.getSignature()); - } - } else { - // No more variations available - fail with an error - throw new AsmFragmentTemplateSynthesizer.UnknownFragmentException("Fragment not found " + initialSignature + ". Attempted variations " + fragmentVariationsTried); - } - } - } - asm.getCurrentChunk().setFragment(fragmentInstance.getFragmentName()); - fragmentInstance.generate(asm); - } - /** * Generate exit-code for entering an interrupt procedure based on the interrupt type * @@ -1006,7 +969,7 @@ public class Pass4CodeGeneration { } try { asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName + ")"); - generateAsm(asm, entryFragment); + AsmFragmentCodeGenerator.generateAsm(asm, entryFragment, program); } catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) { throw new CompileError("Interrupt type not supported " + procedure.getInterruptType() + " int " + procedure + "\n" + e.getMessage()); } @@ -1031,7 +994,7 @@ public class Pass4CodeGeneration { } asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName + ")"); try { - generateAsm(asm, entryFragment); + AsmFragmentCodeGenerator.generateAsm(asm, entryFragment, program); } catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) { throw new CompileError("Interrupt type not supported " + procedure.getInterruptType() + " int " + procedure + "\n" + e.getMessage()); } @@ -1110,7 +1073,7 @@ public class Pass4CodeGeneration { if(isRegisterCopy(lValue, rValue)) { asm.getCurrentChunk().setFragment("register_copy"); } else { - generateAsm(asm, AsmFragmentInstanceSpecBuilder.assignment(lValue, rValue, program, scope)); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.assignment(lValue, rValue, program, scope), program); } } transitionSetGenerated(transition); @@ -1119,57 +1082,6 @@ public class Pass4CodeGeneration { } } - /** - * Ensure that the current encoding in the ASM matches any encoding in the data to be emitted - * - * @param asm The ASM program (where any .encoding directive will be emitted) - * @param asmFragmentInstance The ASM fragment to be emitted - */ - private static void ensureEncoding(AsmProgram asm, AsmFragmentInstanceSpec asmFragmentInstance) { - asm.ensureEncoding(getEncoding(asmFragmentInstance)); - } - - private static void ensureEncoding(AsmProgram asm, Value value) { - asm.ensureEncoding(getEncoding(value)); - } - - /** - * Examine a constantvalue to see if any string encoding information is present - * - * @param value The constant to examine - * @return Any encoding found inside the constant - */ - private static Set getEncoding(Value value) { - LinkedHashSet encodings = new LinkedHashSet<>(); - ProgramValue programValue = new ProgramValue.GenericValue(value); - ProgramValueHandler handler = (ProgramValue pVal, Statement currentStmt, ListIterator stmtIt, ControlFlowBlock currentBlock) -> { - Value val = pVal.get(); - if(val instanceof ConstantChar) { - encodings.add(((ConstantChar) val).getEncoding()); - } else if(val instanceof ConstantString) { - encodings.add(((ConstantString) val).getEncoding()); - } - }; - ProgramValueIterator.execute(programValue, handler, null, null, null); - return encodings; - } - - - /** - * Examine an ASM fragment to see if any string encoding information is present - * - * @param asmFragmentInstance The asm fragment instance to examine - * @return Any encoding found inside the constant - */ - private static Set getEncoding(AsmFragmentInstanceSpec asmFragmentInstance) { - LinkedHashSet encodings = new LinkedHashSet<>(); - Map bindings = asmFragmentInstance.getBindings(); - for(Value boundValue : bindings.values()) { - encodings.addAll(getEncoding(boundValue)); - } - return encodings; - } - /** * Get phi transitions for a specific to-block. *