diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/ProgramScope.java b/src/main/java/dk/camelot64/kickc/model/symbols/ProgramScope.java index e78825414..7f6036f7c 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/ProgramScope.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/ProgramScope.java @@ -4,11 +4,7 @@ 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 { @@ -24,19 +20,6 @@ public class ProgramScope extends Scope { } - /** - * 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 public String toString(Program program, Class symbolClass) { LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = program.getLiveRangeEquivalenceClassSet(); @@ -57,4 +40,10 @@ public class ProgramScope extends Scope { return "program"; } + private TypeDefsScope typeDefsScope = new TypeDefsScope("typedefs", this); + + public Scope getTypeDefScope() { + return typeDefsScope; + } + } diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/TypeDefsScope.java b/src/main/java/dk/camelot64/kickc/model/symbols/TypeDefsScope.java new file mode 100644 index 000000000..283dd1b47 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/model/symbols/TypeDefsScope.java @@ -0,0 +1,22 @@ +package dk.camelot64.kickc.model.symbols; + +import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.types.SymbolType; +import dk.camelot64.kickc.model.types.SymbolTypeTypeDefScope; + +public class TypeDefsScope extends Scope { + + public TypeDefsScope(String name, Scope parentScope) { + super(name, parentScope); + } + + @Override + public SymbolType getType() { + return new SymbolTypeTypeDefScope(); + } + + @Override + public String toString(Program program) { + return "typedefs"; + } +} diff --git a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeTypeDefScope.java b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeTypeDefScope.java new file mode 100644 index 000000000..7f38cfe17 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeTypeDefScope.java @@ -0,0 +1,35 @@ +package dk.camelot64.kickc.model.types; + +/** The scope holding typedefs */ +public class SymbolTypeTypeDefScope implements SymbolType { + + public SymbolTypeTypeDefScope() { + + } + + @Override + public String getTypeName() { + return "TYPEDEF"; + } + + @Override + public int getSizeBytes() { + return -1; + } + + @Override + public int hashCode() { + return 737; + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof SymbolTypeTypeDefScope); + } + + @Override + public String toString() { + return getTypeName(); + } + +} diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java index 1f50f4d97..29f88ff50 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java @@ -454,6 +454,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor { private List declVarComments = null; /** State specifying that we are currently populating struct members. */ private boolean declVarStructMember = false; + /** State specifying that we are currently populating a typedef. */ + private boolean declVarTypeDef = false; /** * Visit the type/directive part of a declaration. Setup the local decl-variables @@ -524,7 +526,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor { // lValue.setDeclaredVolatile(true); //} KickCParser.ExprContext initializer = ctx.expr(); - if(declVarStructMember) { + if(declVarStructMember || declVarTypeDef) { if(initializer != null) { throw new CompileError("Initializers not supported inside structs " + type.getTypeName(), new StatementSource(ctx)); } @@ -1182,7 +1184,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor { } else { structDefName = getCurrentScope().allocateIntermediateVariableName(); } - StructDefinition structDefinition = getCurrentScope().addStructDefinition(structDefName); + StructDefinition structDefinition = program.getScope().addStructDefinition(structDefName); scopeStack.push(structDefinition); declVarStructMember = true; for(KickCParser.StructMembersContext memberCtx : ctx.structMembers()) { @@ -1205,7 +1207,12 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor { @Override public Object visitTypeNamedRef(KickCParser.TypeNamedRefContext ctx) { - throw new InternalError("Not implemented typeef'ed types", new StatementSource(ctx)); + Scope typeDefScope = program.getScope().getTypeDefScope(); + Variable typeDefVariable = typeDefScope.getVariable(ctx.getText()); + if(typeDefVariable!=null) { + return typeDefVariable.getType(); + } + throw new CompileError("Unknown type "+ctx.getText(), new StatementSource(ctx)); } @Override @@ -1249,6 +1256,17 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor { return new SymbolTypeProcedure(returnType); } + @Override + public Object visitTypeDef(KickCParser.TypeDefContext ctx) { + Scope typedefScope = program.getScope().getTypeDefScope(); + scopeStack.push(typedefScope); + this.declVarTypeDef = true; + super.visitTypeDef(ctx); + this.declVarTypeDef = false; + scopeStack.pop(); + return null; + } + @Override public Object visitExprAssignment(KickCParser.ExprAssignmentContext ctx) { Object val = visit(ctx.expr(0)); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2AssertSymbols.java b/src/main/java/dk/camelot64/kickc/passes/Pass2AssertSymbols.java index c6594bdaf..5995c9699 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2AssertSymbols.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2AssertSymbols.java @@ -2,10 +2,7 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.iterator.ProgramValueIterator; -import dk.camelot64.kickc.model.symbols.ConstantVar; -import dk.camelot64.kickc.model.symbols.StructDefinition; -import dk.camelot64.kickc.model.symbols.Symbol; -import dk.camelot64.kickc.model.symbols.VariableUnversioned; +import dk.camelot64.kickc.model.symbols.*; import dk.camelot64.kickc.model.types.SymbolTypeStruct; import dk.camelot64.kickc.model.values.SymbolRef; @@ -45,6 +42,7 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion { if(tableSymbol instanceof VariableUnversioned) continue; if(tableSymbol instanceof ConstantVar) continue; if(tableSymbol instanceof StructDefinition) continue; + if(tableSymbol instanceof TypeDefsScope) continue; if(tableSymbol.getType() instanceof SymbolTypeStruct) continue; Symbol codeSymbol = null; String codeSymbolFullName = tableSymbol.getFullName(); diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 0dddbe7b0..9c6831434 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -35,6 +35,16 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testTypedef1() throws IOException, URISyntaxException { + compileAndCompare("typedef-1"); + } + + @Test + public void testTypedef0() throws IOException, URISyntaxException { + compileAndCompare("typedef-0"); + } + @Test public void testBlackhole() throws IOException, URISyntaxException { compileAndCompare("complex/blackhole/blackhole", log()); diff --git a/src/test/kc/typedef-0.kc b/src/test/kc/typedef-0.kc new file mode 100644 index 000000000..652cc886d --- /dev/null +++ b/src/test/kc/typedef-0.kc @@ -0,0 +1,8 @@ + +typedef byte uint8; + +void main() { + uint8 b = 'a'; + uint8* SCREEN = 0x0400; + *SCREEN = b; +} \ No newline at end of file diff --git a/src/test/kc/typedef-1.kc b/src/test/kc/typedef-1.kc new file mode 100644 index 000000000..5a058e965 --- /dev/null +++ b/src/test/kc/typedef-1.kc @@ -0,0 +1,13 @@ + +typedef byte uint8; + +typedef struct PointDef { + uint8 x; + uint8 y; +} Point; + +void main() { + Point p = { 4, 7 }; + Point* SCREEN = 0x0400; + *SCREEN = p; +} \ No newline at end of file diff --git a/src/test/ref/typedef-0.asm b/src/test/ref/typedef-0.asm new file mode 100644 index 000000000..c2c25f37f --- /dev/null +++ b/src/test/ref/typedef-0.asm @@ -0,0 +1,10 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .const b = 'a' + .label SCREEN = $400 + lda #b + sta SCREEN + rts +} diff --git a/src/test/ref/typedef-0.cfg b/src/test/ref/typedef-0.cfg new file mode 100644 index 000000000..aa1bb1eda --- /dev/null +++ b/src/test/ref/typedef-0.cfg @@ -0,0 +1,15 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0 + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return diff --git a/src/test/ref/typedef-0.log b/src/test/ref/typedef-0.log new file mode 100644 index 000000000..5fb57c292 --- /dev/null +++ b/src/test/ref/typedef-0.log @@ -0,0 +1,219 @@ +Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 +Identified constant variable (byte) main::b +Identified constant variable (byte*) main::SCREEN + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte) main::b#0 ← (byte) 'a' + (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 + *((byte*) main::SCREEN#0) ← (byte) main::b#0 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(byte) main::b +(byte) main::b#0 + +Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 1024 +Successful SSA optimization PassNCastSimplification +Constant (const byte) main::b#0 = 'a' +Constant (const byte*) main::SCREEN#0 = (byte*) 1024 +Successful SSA optimization Pass2ConstantIdentification +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Culled Empty Block (label) @2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0 + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte*) main::SCREEN +(byte) main::b + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +//SEG0 File Comments +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .const b = 'a' + .label SCREEN = $400 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0 -- _deref_pbuc1=vbuc2 + lda #b + sta SCREEN + jmp breturn + //SEG11 main::@return + breturn: + //SEG12 [5] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0 [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 27 combination +Uplifting [] best 27 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .const b = 'a' + .label SCREEN = $400 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0 -- _deref_pbuc1=vbuc2 + lda #b + sta SCREEN + jmp breturn + //SEG11 main::@return + breturn: + //SEG12 [5] return + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(byte) main::b +(const byte) main::b#0 b = (byte) 'a' + + + +FINAL ASSEMBLER +Score: 12 + +//SEG0 File Comments +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .const b = 'a' + .label SCREEN = $400 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0 -- _deref_pbuc1=vbuc2 + lda #b + sta SCREEN + //SEG11 main::@return + //SEG12 [5] return + rts +} + diff --git a/src/test/ref/typedef-0.sym b/src/test/ref/typedef-0.sym new file mode 100644 index 000000000..03b78207b --- /dev/null +++ b/src/test/ref/typedef-0.sym @@ -0,0 +1,10 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(byte) main::b +(const byte) main::b#0 b = (byte) 'a' + diff --git a/src/test/ref/typedef-1.asm b/src/test/ref/typedef-1.asm new file mode 100644 index 000000000..086a8c189 --- /dev/null +++ b/src/test/ref/typedef-1.asm @@ -0,0 +1,14 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const OFFSET_STRUCT_POINTDEF_Y = 1 +main: { + .const p_x = 4 + .const p_y = 7 + .label SCREEN = $400 + lda #p_x + sta SCREEN + lda #p_y + sta SCREEN+OFFSET_STRUCT_POINTDEF_Y + rts +} diff --git a/src/test/ref/typedef-1.cfg b/src/test/ref/typedef-1.cfg new file mode 100644 index 000000000..b59cc0531 --- /dev/null +++ b/src/test/ref/typedef-1.cfg @@ -0,0 +1,16 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] *((byte*)(const struct PointDef*) main::SCREEN#0) ← (const byte) main::p_x#0 + [5] *((byte*)(const struct PointDef*) main::SCREEN#0+(const byte) OFFSET_STRUCT_POINTDEF_Y) ← (const byte) main::p_y#0 + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return diff --git a/src/test/ref/typedef-1.log b/src/test/ref/typedef-1.log new file mode 100644 index 000000000..ddc371bc4 --- /dev/null +++ b/src/test/ref/typedef-1.log @@ -0,0 +1,295 @@ +Created struct value member variable (byte) main::p_x +Created struct value member variable (byte) main::p_y +Converted struct value to member variables (struct PointDef) main::p +Adding struct value list initializer (byte) main::p_x ← (number) 4 +Adding struct value list initializer (byte) main::p_y ← (number) 7 +Adding struct value member variable copy *((byte*) main::$0) ← (byte) main::p_x +Adding struct value member variable copy *((byte*) main::$1) ← (byte) main::p_y +Adding pointer type conversion cast (struct PointDef*) main::SCREEN in (struct PointDef*) main::SCREEN ← (number) $400 +Identified constant variable (struct PointDef*) main::SCREEN +Identified constant variable (byte) main::p_x +Identified constant variable (byte) main::p_y + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte) main::p_x#0 ← (number) 4 + (byte) main::p_y#0 ← (number) 7 + (struct PointDef*) main::SCREEN#0 ← ((struct PointDef*)) (number) $400 + (byte*) main::$0 ← (byte*)(struct PointDef*) main::SCREEN#0 + (const byte) OFFSET_STRUCT_POINTDEF_X + *((byte*) main::$0) ← (byte) main::p_x#0 + (byte*) main::$1 ← (byte*)(struct PointDef*) main::SCREEN#0 + (const byte) OFFSET_STRUCT_POINTDEF_Y + *((byte*) main::$1) ← (byte) main::p_y#0 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(const byte) OFFSET_STRUCT_POINTDEF_X = (byte) 0 +(const byte) OFFSET_STRUCT_POINTDEF_Y = (byte) 1 +(byte) PointDef::x +(byte) PointDef::y +(void()) main() +(byte*) main::$0 +(byte*) main::$1 +(label) main::@return +(struct PointDef*) main::SCREEN +(struct PointDef*) main::SCREEN#0 +(struct PointDef) main::p +(byte) main::p_x +(byte) main::p_x#0 +(byte) main::p_y +(byte) main::p_y#0 + +Adding number conversion cast (unumber) 4 in (byte) main::p_x#0 ← (number) 4 +Adding number conversion cast (unumber) 7 in (byte) main::p_y#0 ← (number) 7 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte) main::p_x#0 ← (unumber)(number) 4 +Inlining cast (byte) main::p_y#0 ← (unumber)(number) 7 +Inlining cast (struct PointDef*) main::SCREEN#0 ← (struct PointDef*)(number) $400 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast 4 +Simplifying constant integer cast 7 +Simplifying constant pointer cast (struct PointDef*) 1024 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 4 +Finalized unsigned number type (byte) 7 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Constant (const byte) main::p_x#0 = 4 +Constant (const byte) main::p_y#0 = 7 +Constant (const struct PointDef*) main::SCREEN#0 = (struct PointDef*) 1024 +Successful SSA optimization Pass2ConstantIdentification +Constant value identified (byte*)main::SCREEN#0 in [3] (byte*) main::$0 ← (byte*)(const struct PointDef*) main::SCREEN#0 + (const byte) OFFSET_STRUCT_POINTDEF_X +Constant value identified (byte*)main::SCREEN#0 in [5] (byte*) main::$1 ← (byte*)(const struct PointDef*) main::SCREEN#0 + (const byte) OFFSET_STRUCT_POINTDEF_Y +Successful SSA optimization Pass2ConstantValues +Converting *(pointer+n) to pointer[n] [4] *((byte*) main::$0) ← (const byte) main::p_x#0 -- *((byte*)main::SCREEN#0 + OFFSET_STRUCT_POINTDEF_X) +Converting *(pointer+n) to pointer[n] [6] *((byte*) main::$1) ← (const byte) main::p_y#0 -- *((byte*)main::SCREEN#0 + OFFSET_STRUCT_POINTDEF_Y) +Successful SSA optimization Pass2InlineDerefIdx +Simplifying expression containing zero (byte*)main::SCREEN#0 in [3] (byte*) main::$0 ← (byte*)(const struct PointDef*) main::SCREEN#0 + (const byte) OFFSET_STRUCT_POINTDEF_X +Simplifying expression containing zero (byte*)main::SCREEN#0 in [4] *((byte*)(const struct PointDef*) main::SCREEN#0 + (const byte) OFFSET_STRUCT_POINTDEF_X) ← (const byte) main::p_x#0 +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused variable (byte*) main::$0 and assignment [0] (byte*) main::$0 ← (byte*)(const struct PointDef*) main::SCREEN#0 +Eliminating unused variable (byte*) main::$1 and assignment [2] (byte*) main::$1 ← (byte*)(const struct PointDef*) main::SCREEN#0 + (const byte) OFFSET_STRUCT_POINTDEF_Y +Eliminating unused constant (const byte) OFFSET_STRUCT_POINTDEF_X +Successful SSA optimization PassNEliminateUnusedVars +Consolidated array index constant in *((byte*)main::SCREEN#0+OFFSET_STRUCT_POINTDEF_Y) +Successful SSA optimization Pass2ConstantAdditionElimination +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Culled Empty Block (label) @2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] *((byte*)(const struct PointDef*) main::SCREEN#0) ← (const byte) main::p_x#0 + [5] *((byte*)(const struct PointDef*) main::SCREEN#0+(const byte) OFFSET_STRUCT_POINTDEF_Y) ← (const byte) main::p_y#0 + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte) PointDef::x +(byte) PointDef::y +(void()) main() +(struct PointDef*) main::SCREEN +(struct PointDef) main::p +(byte) main::p_x +(byte) main::p_y + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +//SEG0 File Comments +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFSET_STRUCT_POINTDEF_Y = 1 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .const p_x = 4 + .const p_y = 7 + .label SCREEN = $400 + //SEG10 [4] *((byte*)(const struct PointDef*) main::SCREEN#0) ← (const byte) main::p_x#0 -- _deref_pbuc1=vbuc2 + lda #p_x + sta SCREEN + //SEG11 [5] *((byte*)(const struct PointDef*) main::SCREEN#0+(const byte) OFFSET_STRUCT_POINTDEF_Y) ← (const byte) main::p_y#0 -- _deref_pbuc1=vbuc2 + lda #p_y + sta SCREEN+OFFSET_STRUCT_POINTDEF_Y + jmp breturn + //SEG12 main::@return + breturn: + //SEG13 [6] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((byte*)(const struct PointDef*) main::SCREEN#0) ← (const byte) main::p_x#0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [5] *((byte*)(const struct PointDef*) main::SCREEN#0+(const byte) OFFSET_STRUCT_POINTDEF_Y) ← (const byte) main::p_y#0 [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [PointDef] +Uplift Scope [main] +Uplift Scope [] + +Uplifting [PointDef] best 33 combination +Uplifting [main] best 33 combination +Uplifting [] best 33 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFSET_STRUCT_POINTDEF_Y = 1 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .const p_x = 4 + .const p_y = 7 + .label SCREEN = $400 + //SEG10 [4] *((byte*)(const struct PointDef*) main::SCREEN#0) ← (const byte) main::p_x#0 -- _deref_pbuc1=vbuc2 + lda #p_x + sta SCREEN + //SEG11 [5] *((byte*)(const struct PointDef*) main::SCREEN#0+(const byte) OFFSET_STRUCT_POINTDEF_Y) ← (const byte) main::p_y#0 -- _deref_pbuc1=vbuc2 + lda #p_y + sta SCREEN+OFFSET_STRUCT_POINTDEF_Y + jmp breturn + //SEG12 main::@return + breturn: + //SEG13 [6] return + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(const byte) OFFSET_STRUCT_POINTDEF_Y OFFSET_STRUCT_POINTDEF_Y = (byte) 1 +(byte) PointDef::x +(byte) PointDef::y +(void()) main() +(label) main::@return +(struct PointDef*) main::SCREEN +(const struct PointDef*) main::SCREEN#0 SCREEN = (struct PointDef*) 1024 +(struct PointDef) main::p +(byte) main::p_x +(const byte) main::p_x#0 p_x = (byte) 4 +(byte) main::p_y +(const byte) main::p_y#0 p_y = (byte) 7 + + + +FINAL ASSEMBLER +Score: 18 + +//SEG0 File Comments +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFSET_STRUCT_POINTDEF_Y = 1 +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .const p_x = 4 + .const p_y = 7 + .label SCREEN = $400 + //SEG10 [4] *((byte*)(const struct PointDef*) main::SCREEN#0) ← (const byte) main::p_x#0 -- _deref_pbuc1=vbuc2 + lda #p_x + sta SCREEN + //SEG11 [5] *((byte*)(const struct PointDef*) main::SCREEN#0+(const byte) OFFSET_STRUCT_POINTDEF_Y) ← (const byte) main::p_y#0 -- _deref_pbuc1=vbuc2 + lda #p_y + sta SCREEN+OFFSET_STRUCT_POINTDEF_Y + //SEG12 main::@return + //SEG13 [6] return + rts +} + diff --git a/src/test/ref/typedef-1.sym b/src/test/ref/typedef-1.sym new file mode 100644 index 000000000..511231669 --- /dev/null +++ b/src/test/ref/typedef-1.sym @@ -0,0 +1,16 @@ +(label) @1 +(label) @begin +(label) @end +(const byte) OFFSET_STRUCT_POINTDEF_Y OFFSET_STRUCT_POINTDEF_Y = (byte) 1 +(byte) PointDef::x +(byte) PointDef::y +(void()) main() +(label) main::@return +(struct PointDef*) main::SCREEN +(const struct PointDef*) main::SCREEN#0 SCREEN = (struct PointDef*) 1024 +(struct PointDef) main::p +(byte) main::p_x +(const byte) main::p_x#0 p_x = (byte) 4 +(byte) main::p_y +(const byte) main::p_y#0 p_y = (byte) 7 +