mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-20 00:29:10 +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 nextConstIdx = 1;
|
||||||
private int nextLabelIdx = 1;
|
private int nextLabelIdx = 1;
|
||||||
|
|
||||||
|
public Map<String, Value> getBindings() {
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
|
||||||
public AsmFragmentInstanceSpecFactory(
|
public AsmFragmentInstanceSpecFactory(
|
||||||
StatementConditionalJump conditionalJump,
|
StatementConditionalJump conditionalJump,
|
||||||
ControlFlowBlock block,
|
ControlFlowBlock block,
|
||||||
|
@ -250,20 +250,20 @@ public interface ProgramValue {
|
|||||||
|
|
||||||
/** A generic Value. */
|
/** A generic Value. */
|
||||||
class GenericValue implements ProgramValue {
|
class GenericValue implements ProgramValue {
|
||||||
private RValue rValue;
|
private Value value;
|
||||||
|
|
||||||
public GenericValue(RValue rValue) {
|
public GenericValue(Value value) {
|
||||||
this.rValue = rValue;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value get() {
|
public Value get() {
|
||||||
return rValue;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(Value value) {
|
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.ControlFlowGraph;
|
||||||
import dk.camelot64.kickc.model.Program;
|
import dk.camelot64.kickc.model.Program;
|
||||||
import dk.camelot64.kickc.model.statements.*;
|
import dk.camelot64.kickc.model.statements.*;
|
||||||
import dk.camelot64.kickc.model.symbols.ConstantVar;
|
import dk.camelot64.kickc.model.symbols.*;
|
||||||
import dk.camelot64.kickc.model.symbols.ProgramScope;
|
|
||||||
import dk.camelot64.kickc.model.symbols.SymbolVariable;
|
|
||||||
import dk.camelot64.kickc.model.types.SymbolTypeArray;
|
import dk.camelot64.kickc.model.types.SymbolTypeArray;
|
||||||
import dk.camelot64.kickc.model.values.*;
|
import dk.camelot64.kickc.model.values.*;
|
||||||
|
|
||||||
@ -232,6 +230,8 @@ public class ProgramValueIterator {
|
|||||||
subValues.add(new ProgramValue.ProgramValueLValueIntermediateVariable((LvalueIntermediate) value));
|
subValues.add(new ProgramValue.ProgramValueLValueIntermediateVariable((LvalueIntermediate) value));
|
||||||
} else if(value == null ||
|
} else if(value == null ||
|
||||||
value instanceof VariableRef ||
|
value instanceof VariableRef ||
|
||||||
|
value instanceof VariableVersion ||
|
||||||
|
value instanceof VariableIntermediate ||
|
||||||
value instanceof ProcedureRef ||
|
value instanceof ProcedureRef ||
|
||||||
value instanceof ConstantLiteral ||
|
value instanceof ConstantLiteral ||
|
||||||
value instanceof ConstantRef ||
|
value instanceof ConstantRef ||
|
||||||
|
@ -34,6 +34,10 @@ public class ConstantChar implements ConstantLiteral<Character> {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConstantString.Encoding getEncoding() {
|
||||||
|
return encoding;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return toString(null);
|
return toString(null);
|
||||||
|
@ -4,6 +4,9 @@ import dk.camelot64.kickc.asm.*;
|
|||||||
import dk.camelot64.kickc.fragment.*;
|
import dk.camelot64.kickc.fragment.*;
|
||||||
import dk.camelot64.kickc.model.*;
|
import dk.camelot64.kickc.model.*;
|
||||||
import dk.camelot64.kickc.model.InternalError;
|
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.operators.Operators;
|
||||||
import dk.camelot64.kickc.model.statements.*;
|
import dk.camelot64.kickc.model.statements.*;
|
||||||
import dk.camelot64.kickc.model.symbols.*;
|
import dk.camelot64.kickc.model.symbols.*;
|
||||||
@ -270,6 +273,8 @@ public class Pass4CodeGeneration {
|
|||||||
added.add(asmName);
|
added.add(asmName);
|
||||||
// Add any comments
|
// Add any comments
|
||||||
generateComments(asm, constantVar.getComments());
|
generateComments(asm, constantVar.getComments());
|
||||||
|
// Ensure encoding is good
|
||||||
|
ensureEncoding(asm, constantVar.getValue());
|
||||||
// Find the constant value calculation
|
// Find the constant value calculation
|
||||||
String asmConstant = AsmFormat.getAsmConstant(program, constantVar.getValue(), 99, scopeRef);
|
String asmConstant = AsmFormat.getAsmConstant(program, constantVar.getValue(), 99, scopeRef);
|
||||||
if(constantVar.getType() instanceof SymbolTypePointer) {
|
if(constantVar.getType() instanceof SymbolTypePointer) {
|
||||||
@ -419,6 +424,7 @@ public class Pass4CodeGeneration {
|
|||||||
asm.addLabel(asmName).setDontOptimize(true);
|
asm.addLabel(asmName).setDontOptimize(true);
|
||||||
for(ConstantValue element : constantArrayList.getElements()) {
|
for(ConstantValue element : constantArrayList.getElements()) {
|
||||||
AsmProgram.AsmDataNumericChunk asmDataChunk = new AsmProgram.AsmDataNumericChunk();
|
AsmProgram.AsmDataNumericChunk asmDataChunk = new AsmProgram.AsmDataNumericChunk();
|
||||||
|
ensureEncoding(asm, element);
|
||||||
addChunkData(asmDataChunk, element, scopeRef);
|
addChunkData(asmDataChunk, element, scopeRef);
|
||||||
asm.addDataNumeric(null, asmDataChunk);
|
asm.addDataNumeric(null, asmDataChunk);
|
||||||
}
|
}
|
||||||
@ -429,6 +435,7 @@ public class Pass4CodeGeneration {
|
|||||||
// Constant array of a "simple" type - add to a single chunk
|
// Constant array of a "simple" type - add to a single chunk
|
||||||
AsmProgram.AsmDataNumericChunk asmDataChunk = new AsmProgram.AsmDataNumericChunk();
|
AsmProgram.AsmDataNumericChunk asmDataChunk = new AsmProgram.AsmDataNumericChunk();
|
||||||
for(ConstantValue element : constantArrayList.getElements()) {
|
for(ConstantValue element : constantArrayList.getElements()) {
|
||||||
|
ensureEncoding(asm, element);
|
||||||
addChunkData(asmDataChunk, element, scopeRef);
|
addChunkData(asmDataChunk, element, scopeRef);
|
||||||
}
|
}
|
||||||
asm.addDataNumeric(asmName, asmDataChunk);
|
asm.addDataNumeric(asmName, asmDataChunk);
|
||||||
@ -436,6 +443,8 @@ public class Pass4CodeGeneration {
|
|||||||
} else if(constantVar.getValue() instanceof ConstantArrayFilled) {
|
} else if(constantVar.getValue() instanceof ConstantArrayFilled) {
|
||||||
ConstantArrayFilled constantArrayFilled = (ConstantArrayFilled) constantVar.getValue();
|
ConstantArrayFilled constantArrayFilled = (ConstantArrayFilled) constantVar.getValue();
|
||||||
ConstantValue arraySize = constantArrayFilled.getSize();
|
ConstantValue arraySize = constantArrayFilled.getSize();
|
||||||
|
// ensure encoding is good
|
||||||
|
ensureEncoding(asm, arraySize);
|
||||||
ConstantLiteral arraySizeConst = arraySize.calculateLiteral(getScope());
|
ConstantLiteral arraySizeConst = arraySize.calculateLiteral(getScope());
|
||||||
if(!(arraySizeConst instanceof ConstantInteger)) {
|
if(!(arraySizeConst instanceof ConstantInteger)) {
|
||||||
throw new Pass2SsaAssertion.AssertionFailed("Error! Array size is not constant integer " + constantVar.toString(program));
|
throw new Pass2SsaAssertion.AssertionFailed("Error! Array size is not constant integer " + constantVar.toString(program));
|
||||||
@ -497,11 +506,8 @@ public class Pass4CodeGeneration {
|
|||||||
try {
|
try {
|
||||||
ConstantLiteral literal = constantVar.getValue().calculateLiteral(getScope());
|
ConstantLiteral literal = constantVar.getValue().calculateLiteral(getScope());
|
||||||
if(literal instanceof ConstantString) {
|
if(literal instanceof ConstantString) {
|
||||||
ConstantString.Encoding stringEncoding = ((ConstantString) literal).getEncoding();
|
// Ensure encoding is good
|
||||||
if(!currentEncoding.equals(stringEncoding)) {
|
ensureEncoding(asm, constantVar.getValue());
|
||||||
asm.addLine(new AsmSetEncoding(stringEncoding));
|
|
||||||
currentEncoding = stringEncoding;
|
|
||||||
}
|
|
||||||
String asmConstant = AsmFormat.getAsmConstant(program, constantVar.getValue(), 99, scopeRef);
|
String asmConstant = AsmFormat.getAsmConstant(program, constantVar.getValue(), 99, scopeRef);
|
||||||
asm.addDataString(asmName.replace("#", "_").replace("$", "_"), asmConstant);
|
asm.addDataString(asmName.replace("#", "_").replace("$", "_"), asmConstant);
|
||||||
added.add(asmName);
|
added.add(asmName);
|
||||||
@ -514,11 +520,12 @@ public class Pass4CodeGeneration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill the data of a constant value into a data chunk
|
* Fill the data of a constant value into a data chunk
|
||||||
*
|
*
|
||||||
* @param dataChunk The 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) {
|
private void addChunkData(AsmProgram.AsmDataNumericChunk dataChunk, ConstantValue value, ScopeRef scopeRef) {
|
||||||
SymbolType elementType = value.getType(program.getScope());
|
SymbolType elementType = value.getType(program.getScope());
|
||||||
@ -538,7 +545,7 @@ public class Pass4CodeGeneration {
|
|||||||
} else if(elementType instanceof SymbolTypePointer) {
|
} else if(elementType instanceof SymbolTypePointer) {
|
||||||
dataChunk.addData(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef));
|
dataChunk.addData(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef));
|
||||||
} else {
|
} 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));
|
//asm.addComment(lValue.toString(program) + " = " + assignment.getrValue2().toString(program) + " // register copy " + getRegister(lValue));
|
||||||
} else {
|
} else {
|
||||||
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(assignment, program);
|
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(assignment, program);
|
||||||
|
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
|
||||||
generateAsm(asm, asmFragmentInstanceSpecFactory);
|
generateAsm(asm, asmFragmentInstanceSpecFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -696,6 +704,7 @@ public class Pass4CodeGeneration {
|
|||||||
if(procedure instanceof PointerDereferenceSimple) {
|
if(procedure instanceof PointerDereferenceSimple) {
|
||||||
RValue pointer = ((PointerDereferenceSimple) procedure).getPointer();
|
RValue pointer = ((PointerDereferenceSimple) procedure).getPointer();
|
||||||
if(pointer instanceof ConstantValue) {
|
if(pointer instanceof ConstantValue) {
|
||||||
|
ensureEncoding(asm, pointer);
|
||||||
asm.addInstruction("jsr", AsmAddressingMode.ABS, AsmFormat.getAsmConstant(program, (ConstantValue) pointer, 99, block.getScope()), false);
|
asm.addInstruction("jsr", AsmAddressingMode.ABS, AsmFormat.getAsmConstant(program, (ConstantValue) pointer, 99, block.getScope()), false);
|
||||||
supported = true;
|
supported = true;
|
||||||
} else if(pointer instanceof VariableRef) {
|
} 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.
|
* Get phi transitions for a specific to-block.
|
||||||
*
|
*
|
||||||
|
@ -38,12 +38,12 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testKcKaStringEncoding() throws IOException, URISyntaxException {
|
public void testKcKaStringEncoding() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("kc-ka-string-encoding", log());
|
compileAndCompare("kc-ka-string-encoding");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGlobalPcMultiple() throws IOException, URISyntaxException {
|
public void testGlobalPcMultiple() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("global-pc-multiple", log());
|
compileAndCompare("global-pc-multiple");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
:BasicUpstart(main)
|
:BasicUpstart(main)
|
||||||
.pc = $80d "Program"
|
.pc = $80d "Program"
|
||||||
main: {
|
main: {
|
||||||
|
.encoding "petscii_mixed"
|
||||||
lda #'e'
|
lda #'e'
|
||||||
sta strTemp+2
|
sta strTemp+2
|
||||||
lda #0
|
lda #0
|
||||||
@ -16,5 +17,4 @@ main: {
|
|||||||
done:
|
done:
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
.encoding "petscii_mixed"
|
|
||||||
strTemp: .text "v=X@"
|
strTemp: .text "v=X@"
|
||||||
|
@ -140,6 +140,7 @@ bend:
|
|||||||
// main
|
// main
|
||||||
main: {
|
main: {
|
||||||
// [4] *((const byte[]) strTemp#0+(byte) 2) ← (byte) 'e'pm -- _deref_pbuc1=vbuc2
|
// [4] *((const byte[]) strTemp#0+(byte) 2) ← (byte) 'e'pm -- _deref_pbuc1=vbuc2
|
||||||
|
.encoding "petscii_mixed"
|
||||||
lda #'e'
|
lda #'e'
|
||||||
sta strTemp+2
|
sta strTemp+2
|
||||||
// [5] *((const byte[]) strTemp#0+(byte) 3) ← (byte) 0 -- _deref_pbuc1=vbuc2
|
// [5] *((const byte[]) strTemp#0+(byte) 3) ← (byte) 0 -- _deref_pbuc1=vbuc2
|
||||||
@ -161,7 +162,6 @@ main: {
|
|||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
.encoding "petscii_mixed"
|
|
||||||
strTemp: .text "v=X@"
|
strTemp: .text "v=X@"
|
||||||
|
|
||||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||||
@ -200,6 +200,7 @@ bend:
|
|||||||
// main
|
// main
|
||||||
main: {
|
main: {
|
||||||
// [4] *((const byte[]) strTemp#0+(byte) 2) ← (byte) 'e'pm -- _deref_pbuc1=vbuc2
|
// [4] *((const byte[]) strTemp#0+(byte) 2) ← (byte) 'e'pm -- _deref_pbuc1=vbuc2
|
||||||
|
.encoding "petscii_mixed"
|
||||||
lda #'e'
|
lda #'e'
|
||||||
sta strTemp+2
|
sta strTemp+2
|
||||||
// [5] *((const byte[]) strTemp#0+(byte) 3) ← (byte) 0 -- _deref_pbuc1=vbuc2
|
// [5] *((const byte[]) strTemp#0+(byte) 3) ← (byte) 0 -- _deref_pbuc1=vbuc2
|
||||||
@ -221,7 +222,6 @@ main: {
|
|||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
.encoding "petscii_mixed"
|
|
||||||
strTemp: .text "v=X@"
|
strTemp: .text "v=X@"
|
||||||
|
|
||||||
ASSEMBLER OPTIMIZATIONS
|
ASSEMBLER OPTIMIZATIONS
|
||||||
@ -274,6 +274,7 @@ Score: 38
|
|||||||
main: {
|
main: {
|
||||||
// strTemp[2] = 'e'
|
// strTemp[2] = 'e'
|
||||||
// [4] *((const byte[]) strTemp#0+(byte) 2) ← (byte) 'e'pm -- _deref_pbuc1=vbuc2
|
// [4] *((const byte[]) strTemp#0+(byte) 2) ← (byte) 'e'pm -- _deref_pbuc1=vbuc2
|
||||||
|
.encoding "petscii_mixed"
|
||||||
lda #'e'
|
lda #'e'
|
||||||
sta strTemp+2
|
sta strTemp+2
|
||||||
// strTemp[3] = 0
|
// strTemp[3] = 0
|
||||||
@ -296,6 +297,5 @@ main: {
|
|||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
// File Data
|
// File Data
|
||||||
.encoding "petscii_mixed"
|
|
||||||
strTemp: .text "v=X@"
|
strTemp: .text "v=X@"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user