1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 17:54:40 +00:00

Code generation now handles encoding in literal chars. Done 2/3 of #245

This commit is contained in:
jespergravgaard 2019-08-04 00:13:33 +02:00
parent 9e56b49a7e
commit 4807bbded7
8 changed files with 111 additions and 21 deletions

View File

@ -43,6 +43,10 @@ public class AsmFragmentInstanceSpecFactory {
private int nextConstIdx = 1;
private int nextLabelIdx = 1;
public Map<String, Value> getBindings() {
return bindings;
}
public AsmFragmentInstanceSpecFactory(
StatementConditionalJump conditionalJump,
ControlFlowBlock block,

View File

@ -250,20 +250,20 @@ public interface ProgramValue {
/** A generic Value. */
class GenericValue implements ProgramValue {
private RValue rValue;
private Value value;
public GenericValue(RValue rValue) {
this.rValue = rValue;
public GenericValue(Value value) {
this.value = value;
}
@Override
public Value get() {
return rValue;
return value;
}
@Override
public void set(Value value) {
this.rValue = (RValue) value;
this.value = value;
}
}

View File

@ -4,9 +4,7 @@ import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.ControlFlowGraph;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.ConstantVar;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.symbols.SymbolVariable;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.SymbolTypeArray;
import dk.camelot64.kickc.model.values.*;
@ -232,6 +230,8 @@ public class ProgramValueIterator {
subValues.add(new ProgramValue.ProgramValueLValueIntermediateVariable((LvalueIntermediate) value));
} else if(value == null ||
value instanceof VariableRef ||
value instanceof VariableVersion ||
value instanceof VariableIntermediate ||
value instanceof ProcedureRef ||
value instanceof ConstantLiteral ||
value instanceof ConstantRef ||

View File

@ -34,6 +34,10 @@ public class ConstantChar implements ConstantLiteral<Character> {
return value;
}
public ConstantString.Encoding getEncoding() {
return encoding;
}
@Override
public String toString() {
return toString(null);

View File

@ -4,6 +4,9 @@ import dk.camelot64.kickc.asm.*;
import dk.camelot64.kickc.fragment.*;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.InternalError;
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.*;
@ -270,6 +273,8 @@ public class Pass4CodeGeneration {
added.add(asmName);
// Add any comments
generateComments(asm, constantVar.getComments());
// Ensure encoding is good
ensureEncoding(asm, constantVar.getValue());
// Find the constant value calculation
String asmConstant = AsmFormat.getAsmConstant(program, constantVar.getValue(), 99, scopeRef);
if(constantVar.getType() instanceof SymbolTypePointer) {
@ -419,6 +424,7 @@ public class Pass4CodeGeneration {
asm.addLabel(asmName).setDontOptimize(true);
for(ConstantValue element : constantArrayList.getElements()) {
AsmProgram.AsmDataNumericChunk asmDataChunk = new AsmProgram.AsmDataNumericChunk();
ensureEncoding(asm, element);
addChunkData(asmDataChunk, element, scopeRef);
asm.addDataNumeric(null, asmDataChunk);
}
@ -429,6 +435,7 @@ public class Pass4CodeGeneration {
// Constant array of a "simple" type - add to a single chunk
AsmProgram.AsmDataNumericChunk asmDataChunk = new AsmProgram.AsmDataNumericChunk();
for(ConstantValue element : constantArrayList.getElements()) {
ensureEncoding(asm, element);
addChunkData(asmDataChunk, element, scopeRef);
}
asm.addDataNumeric(asmName, asmDataChunk);
@ -436,6 +443,8 @@ public class Pass4CodeGeneration {
} else if(constantVar.getValue() instanceof ConstantArrayFilled) {
ConstantArrayFilled constantArrayFilled = (ConstantArrayFilled) constantVar.getValue();
ConstantValue arraySize = constantArrayFilled.getSize();
// ensure encoding is good
ensureEncoding(asm, arraySize);
ConstantLiteral arraySizeConst = arraySize.calculateLiteral(getScope());
if(!(arraySizeConst instanceof ConstantInteger)) {
throw new Pass2SsaAssertion.AssertionFailed("Error! Array size is not constant integer " + constantVar.toString(program));
@ -497,11 +506,8 @@ public class Pass4CodeGeneration {
try {
ConstantLiteral literal = constantVar.getValue().calculateLiteral(getScope());
if(literal instanceof ConstantString) {
ConstantString.Encoding stringEncoding = ((ConstantString) literal).getEncoding();
if(!currentEncoding.equals(stringEncoding)) {
asm.addLine(new AsmSetEncoding(stringEncoding));
currentEncoding = stringEncoding;
}
// Ensure encoding is good
ensureEncoding(asm, constantVar.getValue());
String asmConstant = AsmFormat.getAsmConstant(program, constantVar.getValue(), 99, scopeRef);
asm.addDataString(asmName.replace("#", "_").replace("$", "_"), asmConstant);
added.add(asmName);
@ -514,11 +520,12 @@ public class Pass4CodeGeneration {
}
}
/**
* Fill the data of a constant value into a data chunk
*
* @param dataChunk The data chunk
* @param structValue The constant value
* @param value The constant value
*/
private void addChunkData(AsmProgram.AsmDataNumericChunk dataChunk, ConstantValue value, ScopeRef scopeRef) {
SymbolType elementType = value.getType(program.getScope());
@ -538,7 +545,7 @@ public class Pass4CodeGeneration {
} else if(elementType instanceof SymbolTypePointer) {
dataChunk.addData(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef));
} else {
throw new InternalError("Unhandled array element type "+elementType.toString()+ " value "+value.toString(program));
throw new InternalError("Unhandled array element type " + elementType.toString() + " value " + value.toString(program));
}
}
@ -629,6 +636,7 @@ public class Pass4CodeGeneration {
//asm.addComment(lValue.toString(program) + " = " + assignment.getrValue2().toString(program) + " // register copy " + getRegister(lValue));
} else {
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(assignment, program);
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
generateAsm(asm, asmFragmentInstanceSpecFactory);
}
}
@ -696,6 +704,7 @@ public class Pass4CodeGeneration {
if(procedure instanceof PointerDereferenceSimple) {
RValue pointer = ((PointerDereferenceSimple) procedure).getPointer();
if(pointer instanceof ConstantValue) {
ensureEncoding(asm, pointer);
asm.addInstruction("jsr", AsmAddressingMode.ABS, AsmFormat.getAsmConstant(program, (ConstantValue) pointer, 99, block.getScope()), false);
supported = true;
} else if(pointer instanceof VariableRef) {
@ -916,6 +925,79 @@ 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 void ensureEncoding(AsmProgram asm, AsmFragmentInstanceSpecFactory asmFragmentInstance) {
ensureEncoding(asm, getEncoding(asmFragmentInstance));
}
private void ensureEncoding(AsmProgram asm, Value value) {
ensureEncoding(asm, getEncoding(value));
}
/**
* 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 encodings The encodings to ensure
*/
private void ensureEncoding(AsmProgram asm, Collection<ConstantString.Encoding> encodings) {
if(encodings == null || encodings.size()==0) return;
if(encodings.size()>1) {
throw new CompileError("Different character encodings in one ASM statement not supported!");
}
// Size is 1 - grab it!
ConstantString.Encoding encoding = encodings.iterator().next();
if(!currentEncoding.equals(encoding)) {
asm.addLine(new AsmSetEncoding(encoding));
currentEncoding = encoding;
}
}
/**
* 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 Set<ConstantString.Encoding> getEncoding(Value value) {
LinkedHashSet<ConstantString.Encoding> 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 Set<ConstantString.Encoding> getEncoding(AsmFragmentInstanceSpecFactory asmFragmentInstance) {
LinkedHashSet<ConstantString.Encoding> 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.
*

View File

@ -38,12 +38,12 @@ public class TestPrograms {
@Test
public void testKcKaStringEncoding() throws IOException, URISyntaxException {
compileAndCompare("kc-ka-string-encoding", log());
compileAndCompare("kc-ka-string-encoding");
}
@Test
public void testGlobalPcMultiple() throws IOException, URISyntaxException {
compileAndCompare("global-pc-multiple", log());
compileAndCompare("global-pc-multiple");
}

View File

@ -2,6 +2,7 @@
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.encoding "petscii_mixed"
lda #'e'
sta strTemp+2
lda #0
@ -16,5 +17,4 @@ main: {
done:
rts
}
.encoding "petscii_mixed"
strTemp: .text "v=X@"

View File

@ -140,6 +140,7 @@ bend:
// main
main: {
// [4] *((const byte[]) strTemp#0+(byte) 2) ← (byte) 'e'pm -- _deref_pbuc1=vbuc2
.encoding "petscii_mixed"
lda #'e'
sta strTemp+2
// [5] *((const byte[]) strTemp#0+(byte) 3) ← (byte) 0 -- _deref_pbuc1=vbuc2
@ -161,7 +162,6 @@ main: {
rts
}
// File Data
.encoding "petscii_mixed"
strTemp: .text "v=X@"
REGISTER UPLIFT POTENTIAL REGISTERS
@ -200,6 +200,7 @@ bend:
// main
main: {
// [4] *((const byte[]) strTemp#0+(byte) 2) ← (byte) 'e'pm -- _deref_pbuc1=vbuc2
.encoding "petscii_mixed"
lda #'e'
sta strTemp+2
// [5] *((const byte[]) strTemp#0+(byte) 3) ← (byte) 0 -- _deref_pbuc1=vbuc2
@ -221,7 +222,6 @@ main: {
rts
}
// File Data
.encoding "petscii_mixed"
strTemp: .text "v=X@"
ASSEMBLER OPTIMIZATIONS
@ -274,6 +274,7 @@ Score: 38
main: {
// strTemp[2] = 'e'
// [4] *((const byte[]) strTemp#0+(byte) 2) ← (byte) 'e'pm -- _deref_pbuc1=vbuc2
.encoding "petscii_mixed"
lda #'e'
sta strTemp+2
// strTemp[3] = 0
@ -296,6 +297,5 @@ main: {
rts
}
// File Data
.encoding "petscii_mixed"
strTemp: .text "v=X@"