mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-17 10:30:43 +00:00
Code generation now handles encoding in literal chars. Done 2/3 of #245
This commit is contained in:
parent
9e56b49a7e
commit
4807bbded7
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 ||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
@ -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@"
|
||||
|
@ -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@"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user