1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-02-16 18:30:37 +00:00

Testing structs

This commit is contained in:
jespergravgaard 2019-05-28 22:28:17 +02:00
parent 30d6878ade
commit 9c682e37fe
16 changed files with 204 additions and 33 deletions

View File

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

View File

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

View File

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

View File

@ -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 {

View File

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

View File

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

View File

@ -40,7 +40,6 @@ public class SymbolTypeProcedure implements SymbolType {
@Override
public int hashCode() {
return Objects.hash(returnType);
}
}

View File

@ -48,7 +48,6 @@ public class SymbolTypeStruct implements SymbolType {
@Override
public int hashCode() {
return Objects.hash(name, sizeBytes);
}

View File

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

View File

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

View 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;
}

View File

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

View 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
}

View File

@ -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
View 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
}