1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-03 07:29:37 +00:00

Moved ASM code gen and ASM encoding handling into separate util classes.

This commit is contained in:
jespergravgaard 2021-12-27 00:33:30 +01:00
parent 87cc51d685
commit 44ec5be5e8
4 changed files with 135 additions and 110 deletions

View File

@ -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<StringEncoding> getEncoding(Value value) {
LinkedHashSet<StringEncoding> encodings = new LinkedHashSet<>();
ProgramValue programValue = new ProgramValue.GenericValue(value);
ProgramValueHandler handler = (ProgramValue pVal, Statement currentStmt, ListIterator<Statement> 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<StringEncoding> getEncoding(AsmFragmentInstanceSpec asmFragmentInstance) {
LinkedHashSet<StringEncoding> encodings = new LinkedHashSet<>();
Map<String, Value> bindings = asmFragmentInstance.getBindings();
for(Value boundValue : bindings.values()) {
encodings.addAll(getEncoding(boundValue));
}
return encodings;
}
}

View File

@ -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);
}
}

View File

@ -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
*/

View File

@ -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<StringEncoding> getEncoding(Value value) {
LinkedHashSet<StringEncoding> encodings = new LinkedHashSet<>();
ProgramValue programValue = new ProgramValue.GenericValue(value);
ProgramValueHandler handler = (ProgramValue pVal, Statement currentStmt, ListIterator<Statement> 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<StringEncoding> getEncoding(AsmFragmentInstanceSpec asmFragmentInstance) {
LinkedHashSet<StringEncoding> encodings = new LinkedHashSet<>();
Map<String, Value> bindings = asmFragmentInstance.getBindings();
for(Value boundValue : bindings.values()) {
encodings.addAll(getEncoding(boundValue));
}
return encodings;
}
/**
* Get phi transitions for a specific to-block.
*