mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-16 18:30:37 +00:00
Testing structs
This commit is contained in:
parent
30d6878ade
commit
9c682e37fe
@ -159,7 +159,7 @@ public class Compiler {
|
||||
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("SYMBOLS");
|
||||
getLog().append(program.getScope().getSymbolTableContents(program));
|
||||
getLog().append(program.getScope().toString(program, null));
|
||||
}
|
||||
|
||||
new Pass1FixLValuesLoHi(program).execute();
|
||||
@ -206,7 +206,7 @@ public class Compiler {
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
getLog().append("SYMBOL TABLE SSA");
|
||||
getLog().append(program.getScope().getSymbolTableContents(program));
|
||||
getLog().append(program.getScope().toString(program, null));
|
||||
|
||||
return program;
|
||||
}
|
||||
@ -530,7 +530,7 @@ public class Compiler {
|
||||
new Pass5FixLongBranches(program).optimize();
|
||||
|
||||
getLog().append("\nFINAL SYMBOL TABLE");
|
||||
getLog().append(program.getScope().getSymbolTableContents(program));
|
||||
getLog().append(program.getScope().toString(program, null));
|
||||
|
||||
getLog().append("\nFINAL ASSEMBLER");
|
||||
getLog().append("Score: " + Pass4RegisterUpliftCombinations.getAsmScore(program) + "\n");
|
||||
|
@ -3,14 +3,12 @@ package dk.camelot64.kickc.fragment;
|
||||
import dk.camelot64.kickc.NumberParser;
|
||||
import dk.camelot64.kickc.asm.*;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.values.ConstantInteger;
|
||||
import dk.camelot64.kickc.model.values.ConstantValue;
|
||||
import dk.camelot64.kickc.model.symbols.StructDefinition;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
import dk.camelot64.kickc.model.symbols.ConstantVar;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
import dk.camelot64.kickc.model.values.Value;
|
||||
import dk.camelot64.kickc.parser.KickCBaseVisitor;
|
||||
import dk.camelot64.kickc.parser.KickCParser;
|
||||
|
||||
@ -97,6 +95,16 @@ public class AsmFragmentInstance {
|
||||
} else if(boundValue instanceof Label) {
|
||||
String param = ((Label) boundValue).getLocalName().replace('@', 'b').replace(':', '_').replace("$", "_");
|
||||
return new AsmParameter(param, false);
|
||||
} else if(boundValue instanceof StructMemberRef) {
|
||||
StructMemberRef structMemberRef = (StructMemberRef) boundValue;
|
||||
StructDefinition structDefinition = program.getScope().getStructDefinition(structMemberRef);
|
||||
Variable structMember = structDefinition.getMember(structMemberRef.getMemberName());
|
||||
int memberByteOffset = structDefinition.getMemberByteOffset(structMember);
|
||||
VariableRef struct = (VariableRef) structMemberRef.getStruct();
|
||||
Variable structVar = program.getScope().getVariable( struct);
|
||||
Registers.RegisterZpStruct structRegister = (Registers.RegisterZpStruct) structVar.getAllocation();
|
||||
// TODO Use STRUCT_OFFSET constants instead of hardcoded constants
|
||||
return new AsmParameter(AsmFormat.getAsmParamName(structVar, codeScopeRef)+"+"+memberByteOffset,true);
|
||||
} else {
|
||||
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
|
||||
}
|
||||
|
@ -249,9 +249,9 @@ public class AsmFragmentInstanceSpecFactory {
|
||||
} else if(constantLiteral instanceof ConstantPointer) {
|
||||
integerValue = ((ConstantPointer) constantLiteral).getValue();
|
||||
} else {
|
||||
throw new InternalError("Not implemented "+constantLiteral);
|
||||
throw new InternalError("Not implemented " + constantLiteral);
|
||||
}
|
||||
} catch (ConstantNotLiteral e) {
|
||||
} catch(ConstantNotLiteral e) {
|
||||
// Assume it is a word
|
||||
integerValue = 0xffffL;
|
||||
}
|
||||
@ -262,7 +262,7 @@ public class AsmFragmentInstanceSpecFactory {
|
||||
} else if(toType.getSizeBytes() == 2) {
|
||||
val = new ConstantBinary(new ConstantInteger(0xffffL, SymbolType.WORD), Operators.BOOL_AND, val);
|
||||
} else {
|
||||
throw new InternalError("Not implemented "+toType);
|
||||
throw new InternalError("Not implemented " + toType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -304,25 +304,26 @@ public class AsmFragmentInstanceSpecFactory {
|
||||
bind(name, value);
|
||||
return name;
|
||||
} else if(value instanceof StructZero) {
|
||||
return "vssf"+((StructZero) value).getTypeStruct().getSizeBytes();
|
||||
return "vssf" + ((StructZero) value).getTypeStruct().getSizeBytes();
|
||||
} else if(value instanceof StructMemberRef) {
|
||||
StructMemberRef structMemberRef = (StructMemberRef) value;
|
||||
StructDefinition structDefinition = program.getScope().getStructDefinition(structMemberRef);
|
||||
Variable structMember = structDefinition.getMember(structMemberRef.getMemberName());
|
||||
int memberByteOffset = structDefinition.getMemberByteOffset(structMember);
|
||||
|
||||
RValue struct = structMemberRef.getStruct();
|
||||
String memberName = structMemberRef.getMemberName();
|
||||
SymbolType symbolType = SymbolTypeInference.inferType(program.getScope(), struct);
|
||||
byte idx = 0;
|
||||
if(symbolType instanceof SymbolTypeStruct) {
|
||||
String structTypeName = ((SymbolTypeStruct) symbolType).getStructTypeName();
|
||||
StructDefinition structDefinition = program.getScope().getStructDefinition(structTypeName);
|
||||
for(Variable structMember : structDefinition.getAllVariables(false)) {
|
||||
if(structMember.getLocalName().equals(memberName)) {
|
||||
break;
|
||||
} else {
|
||||
idx += structMember.getType().getSizeBytes();
|
||||
}
|
||||
if(struct instanceof VariableRef) {
|
||||
Variable structVar = program.getScope().getVariable((VariableRef) struct);
|
||||
if(structVar.getAllocation() instanceof Registers.RegisterZpStruct) {
|
||||
Registers.RegisterZpStruct structRegister = (Registers.RegisterZpStruct) structVar.getAllocation();
|
||||
Registers.RegisterZpStructMember memberRegister = structRegister.getMemberRegister(memberByteOffset);
|
||||
String name = getTypePrefix(structMember.getType()) + getRegisterName(memberRegister);
|
||||
bind(name, structMemberRef);
|
||||
return name;
|
||||
}
|
||||
} else {
|
||||
return bind(struct) + "_mbr_" + memberByteOffset;
|
||||
}
|
||||
return bind(struct)+"_mbr_"+ idx;
|
||||
}
|
||||
throw new RuntimeException("Binding of value type not supported " + value);
|
||||
}
|
||||
|
@ -105,6 +105,7 @@ public class Registers {
|
||||
public int hashCode() {
|
||||
return zp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -158,6 +159,10 @@ public class Registers {
|
||||
super(zp);
|
||||
}
|
||||
|
||||
public RegisterZpStructMember getMemberRegister(int memberByteOffset) {
|
||||
return new RegisterZpStructMember(getZp()+memberByteOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterType getType() {
|
||||
return RegisterType.ZP_STRUCT;
|
||||
@ -165,6 +170,21 @@ public class Registers {
|
||||
|
||||
}
|
||||
|
||||
/** Zero page addresses used as a register for a struct member variable. */
|
||||
public static class RegisterZpStructMember extends RegisterZp {
|
||||
|
||||
public RegisterZpStructMember(int zp) {
|
||||
super(zp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterType getType() {
|
||||
return RegisterType.ZP_STRUCT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** A zero page address used as a register for a boolean variable. */
|
||||
public static class RegisterZpBool extends RegisterZp {
|
||||
|
||||
|
@ -4,7 +4,11 @@ import dk.camelot64.kickc.model.LiveRangeEquivalenceClass;
|
||||
import dk.camelot64.kickc.model.LiveRangeEquivalenceClassSet;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeProgram;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.StructMemberRef;
|
||||
|
||||
/** The program scope containing the symbols of a program */
|
||||
public class ProgramScope extends Scope {
|
||||
@ -19,8 +23,18 @@ public class ProgramScope extends Scope {
|
||||
return new SymbolTypeProgram();
|
||||
}
|
||||
|
||||
public String getSymbolTableContents(Program program) {
|
||||
return toString(program, null);
|
||||
|
||||
/**
|
||||
* Get the struct definition for a struct
|
||||
* @param structMemberRef
|
||||
* @return
|
||||
*/
|
||||
public StructDefinition getStructDefinition(StructMemberRef structMemberRef) {
|
||||
RValue struct = structMemberRef.getStruct();
|
||||
SymbolType structType = SymbolTypeInference.inferType(this, struct);
|
||||
String structTypeName = ((SymbolTypeStruct) structType).getStructTypeName();
|
||||
StructDefinition structDefinition = getStructDefinition(structTypeName);
|
||||
return structDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,6 +18,37 @@ public class StructDefinition extends Scope {
|
||||
return new SymbolTypeStruct(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a struct member variable
|
||||
* @param name The name of the member
|
||||
* @return The member variable
|
||||
*/
|
||||
public Variable getMember(String name) {
|
||||
for(Variable member : getAllVariables(false)) {
|
||||
if(member.getLocalName().equals(name)) {
|
||||
return member;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bytes that the member data is offset from the start of the struct
|
||||
* @param member The member to find offset for
|
||||
* @return The byte offset of the start of the member data
|
||||
*/
|
||||
public int getMemberByteOffset(Variable member) {
|
||||
int byteOffset=0;
|
||||
for(Variable structMember : getAllVariables(false)) {
|
||||
if(structMember.equals(member)) {
|
||||
break;
|
||||
} else {
|
||||
byteOffset += structMember.getType().getSizeBytes();
|
||||
}
|
||||
}
|
||||
return byteOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Program program) {
|
||||
return "block-"+getFullName();
|
||||
|
@ -40,7 +40,6 @@ public class SymbolTypeProcedure implements SymbolType {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
return Objects.hash(returnType);
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,6 @@ public class SymbolTypeStruct implements SymbolType {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
return Objects.hash(name, sizeBytes);
|
||||
}
|
||||
|
||||
|
@ -1154,6 +1154,13 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
return structDefinition.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitStructRef(KickCParser.StructRefContext ctx) {
|
||||
String structDefName = ctx.NAME().getText();
|
||||
StructDefinition structDefinition = getCurrentScope().getStructDefinition(structDefName);
|
||||
return structDefinition.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType visitTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx) {
|
||||
String signedness = ctx.getChild(0).getText();
|
||||
|
@ -32,9 +32,19 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStruct1() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStruct0() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-0", log().verboseCreateSsa().verboseParse().verboseStatementSequence());
|
||||
compileAndCompare("struct-0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForTwoVars() throws IOException, URISyntaxException {
|
||||
compileAndCompare("for-two-vars");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -49,7 +59,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testConstantStringConcat0() throws IOException, URISyntaxException {
|
||||
compileAndCompare("constant-string-concat-0", log().verboseParse().verboseStatementSequence().verboseCreateSsa());
|
||||
compileAndCompare("constant-string-concat-0");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -57,7 +67,6 @@ public class TestPrograms {
|
||||
compileAndCompare("literals");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testConstantStringConcat() throws IOException, URISyntaxException {
|
||||
compileAndCompare("constant-string-concat");
|
||||
|
9
src/test/kc/for-two-vars.kc
Normal file
9
src/test/kc/for-two-vars.kc
Normal file
@ -0,0 +1,9 @@
|
||||
// Test a for-loop with two iterating variables
|
||||
// Illustrates that for()-loops currently cannot contain two variable declarations.
|
||||
|
||||
void main() {
|
||||
const byte* SCREEN = 0x400;
|
||||
byte *sc=SCREEN+39;
|
||||
for( byte i=0; i<40; i++, sc--)
|
||||
*sc = i;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Minimal struct - declaration &
|
||||
// Minimal struct - declaration, instantiation and usage
|
||||
|
||||
struct Point {
|
||||
byte x;
|
||||
|
18
src/test/kc/struct-1.kc
Normal file
18
src/test/kc/struct-1.kc
Normal file
@ -0,0 +1,18 @@
|
||||
// Minimal struct - two instances being used.
|
||||
|
||||
struct Point {
|
||||
byte x;
|
||||
byte y;
|
||||
};
|
||||
|
||||
struct Point point1, point2;
|
||||
|
||||
void main() {
|
||||
point1.x = 2;
|
||||
point1.y = 3;
|
||||
point2.x = point1.y;
|
||||
point2.y = point1.x;
|
||||
const byte* SCREEN = 0x0400;
|
||||
SCREEN[0] = point2.x;
|
||||
SCREEN[1] = point2.y;
|
||||
}
|
27
src/test/ref/for-two-vars.asm
Normal file
27
src/test/ref/for-two-vars.asm
Normal file
@ -0,0 +1,27 @@
|
||||
// Test a for-loop with two iterating variables
|
||||
// Illustrates that for()-loops currently cannot contain two variable declarations.
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.label sc = 2
|
||||
lda #<SCREEN+$27
|
||||
sta sc
|
||||
lda #>SCREEN+$27
|
||||
sta sc+1
|
||||
ldx #0
|
||||
b1:
|
||||
txa
|
||||
ldy #0
|
||||
sta (sc),y
|
||||
inx
|
||||
lda sc
|
||||
bne !+
|
||||
dec sc+1
|
||||
!:
|
||||
dec sc
|
||||
cpx #$28
|
||||
bcc b1
|
||||
rts
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Minimal struct - declaration &
|
||||
// Minimal struct - declaration, instantiation and usage
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
|
29
src/test/ref/struct-1.asm
Normal file
29
src/test/ref/struct-1.asm
Normal file
@ -0,0 +1,29 @@
|
||||
// Minimal struct - two instances being used.
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
.label point1 = 2
|
||||
.label point2 = 4
|
||||
bbegin:
|
||||
lda #0
|
||||
sta point1
|
||||
sta point1+1
|
||||
sta point2
|
||||
sta point2+1
|
||||
jsr main
|
||||
rts
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
lda #2
|
||||
sta point1+0
|
||||
lda #3
|
||||
sta point1+1
|
||||
sta point2+0
|
||||
lda point1+0
|
||||
sta point2+1
|
||||
lda point2+0
|
||||
sta SCREEN
|
||||
lda point2+1
|
||||
sta SCREEN+1
|
||||
rts
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user