1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-10-21 02:24:34 +00:00

Implemented enum support (excl. complex constant usage in values). Closes #119

This commit is contained in:
jespergravgaard 2019-06-19 00:39:15 +02:00
parent e4af001041
commit 10082a5d96
26 changed files with 1484 additions and 432 deletions

View File

@ -0,0 +1,25 @@
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.SymbolTypeEnum;
public class EnumDefinition extends Scope {
public EnumDefinition(String name, Scope parentScope) {
super(name, parentScope);
}
@Override
public SymbolType getType() {
return new SymbolTypeEnum(this);
}
@Override
public String toString(Program program) {
return "enum-"+getFullName();
}
}

View File

@ -301,6 +301,11 @@ public abstract class Scope implements Symbol {
return (StructDefinition) getSymbol(name);
}
public EnumDefinition getEnumDefinition(String name) {
return (EnumDefinition) getSymbol(name);
}
public Scope getScope(ScopeRef scopeRef) {
if(scopeRef.getFullName().equals("") && this instanceof ProgramScope) {
// Special case for the outer program scope

View File

@ -51,6 +51,6 @@ public class StructDefinition extends Scope {
@Override
public String toString(Program program) {
return "block-"+getFullName();
return "struct-"+getFullName();
}
}

View File

@ -0,0 +1,53 @@
package dk.camelot64.kickc.model.types;
import dk.camelot64.kickc.model.symbols.EnumDefinition;
import java.util.Objects;
/** An enum */
public class SymbolTypeEnum implements SymbolType {
/** Name of the enum type. */
private String name;
/** The enum definition. */
private EnumDefinition definition;
public SymbolTypeEnum(EnumDefinition definition) {
this.definition = definition;
this.name = definition.getLocalName();
}
@Override
public String getTypeName() {
return "enum " + name;
}
@Override
public int getSizeBytes() {
return 1;
}
public EnumDefinition getDefinition() {
return definition;
}
@Override
public String toString() {
return getTypeName();
}
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
SymbolTypeEnum that = (SymbolTypeEnum) o;
return Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}

View File

@ -146,7 +146,7 @@ enumRef
;
enumDef
: 'enum' NAME '{' enumMemberList '}'
: 'enum' NAME? '{' enumMemberList '}'
;
enumMemberList

File diff suppressed because it is too large Load Diff

View File

@ -4,11 +4,7 @@ import dk.camelot64.kickc.Compiler;
import dk.camelot64.kickc.NumberParser;
import dk.camelot64.kickc.asm.AsmClobber;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.operators.Operator;
import dk.camelot64.kickc.model.operators.OperatorSizeOf;
import dk.camelot64.kickc.model.operators.OperatorTypeId;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.operators.*;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.*;
@ -522,9 +518,6 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
// Add comments to constant
lValue.setComments(ensureUnusedComments(comments));
}
//if(type instanceof SymbolTypeStruct) {
// lValue.setDeclaredVolatile(true);
//}
KickCParser.ExprContext initializer = ctx.expr();
if(declVarStructMember || declVarTypeDef) {
if(initializer != null) {
@ -1205,6 +1198,80 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
return structDefinition.getType();
}
@Override
public Object visitTypeEnumDef(KickCParser.TypeEnumDefContext ctx) {
return visit(ctx.enumDef());
}
private EnumDefinition currentEnum = null;
@Override
public Object visitEnumDef(KickCParser.EnumDefContext ctx) {
String enumDefName;
if(ctx.NAME() != null) {
enumDefName = ctx.NAME().getText();
} else {
enumDefName = getCurrentScope().allocateIntermediateVariableName();
}
EnumDefinition enumDefinition = new EnumDefinition(enumDefName, getCurrentScope());
getCurrentScope().add(enumDefinition);
this.currentEnum = enumDefinition;
scopeStack.push(currentEnum);
visit(ctx.enumMemberList());
scopeStack.pop();
this.currentEnum = null;
// Copy all members to upper-level scope
for(ConstantVar member : enumDefinition.getAllConstants(false)) {
getCurrentScope().add(new ConstantVar(member.getLocalName(), getCurrentScope(), SymbolType.BYTE, member.getValue()));
}
return SymbolType.BYTE;
}
@Override
public Object visitEnumMember(KickCParser.EnumMemberContext ctx) {
String memberName = ctx.NAME().getText();
ConstantValue enumValue;
if(ctx.expr()!=null) {
RValue exprVal = (RValue) visit(ctx.expr());
if(!(exprVal instanceof ConstantValue)) {
throw new CompileError("Enum value not constant "+memberName, new StatementSource(ctx));
}
enumValue = (ConstantValue) exprVal;
} else {
// No specific value - find previous value
List<ConstantVar> values = new ArrayList<>(currentEnum.getAllConstants(false));
if(values.isEmpty()) {
enumValue = new ConstantInteger(0L, SymbolType.BYTE);
} else {
ConstantVar prevEnumMember= values.get(values.size() - 1);
ConstantValue prevValue = prevEnumMember.getValue();
if(prevValue instanceof ConstantInteger) {
enumValue = new ConstantInteger(((ConstantInteger) prevValue).getInteger()+1, SymbolType.BYTE);
} else {
enumValue = new ConstantBinary(prevValue, Operators.PLUS, new ConstantInteger(1L, SymbolType.BYTE));
}
}
}
currentEnum.add(new ConstantVar(memberName, getCurrentScope(), SymbolType.BYTE, enumValue));
return null;
}
@Override
public Object visitTypeEnumRef(KickCParser.TypeEnumRefContext ctx) {
return visit(ctx.enumRef());
}
@Override
public Object visitEnumRef(KickCParser.EnumRefContext ctx) {
String enumDefName = ctx.NAME().getText();
EnumDefinition enumDefinition = getCurrentScope().getEnumDefinition(enumDefName);
if(enumDefinition==null) {
throw new CompileError("Unknown enum "+enumDefName, new StatementSource(ctx));
}
return SymbolType.BYTE;
}
@Override
public Object visitTypeNamedRef(KickCParser.TypeNamedRefContext ctx) {
Scope typeDefScope = program.getScope().getTypeDefScope();
@ -1494,11 +1561,15 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
RValue right = (RValue) this.visit(ctx.expr(1));
String op = ((TerminalNode) ctx.getChild(1)).getSymbol().getText();
Operator operator = Operators.getBinary(op);
VariableIntermediate tmpVar = getCurrentScope().addVariableIntermediate();
VariableRef tmpVarRef = tmpVar.getRef();
Statement stmt = new StatementAssignment(tmpVarRef, left, operator, right, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx)));
sequence.addStatement(stmt);
return tmpVarRef;
// if(left instanceof ConstantValue && right instanceof ConstantValue) {
// return new ConstantBinary((ConstantValue) left, (OperatorBinary) operator, (ConstantValue) right);
// } else {
VariableIntermediate tmpVar = getCurrentScope().addVariableIntermediate();
VariableRef tmpVarRef = tmpVar.getRef();
Statement stmt = new StatementAssignment(tmpVarRef, left, operator, right, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx)));
sequence.addStatement(stmt);
return tmpVarRef;
// }
}
@Override
@ -1515,6 +1586,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
// Special handling of negative literal number
if(child instanceof ConstantInteger && operator.equals(Operators.NEG)) {
return new ConstantInteger(-((ConstantInteger) child).getInteger(), ((ConstantInteger) child).getType());
// } else if(child instanceof ConstantValue) {
// return new ConstantUnary((OperatorUnary) operator, (ConstantValue) child);
} else {
VariableIntermediate tmpVar = getCurrentScope().addVariableIntermediate();
VariableRef tmpVarRef = tmpVar.getRef();
@ -1588,6 +1661,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
} else if(symbol instanceof Procedure) {
Procedure procedure = (Procedure) symbol;
return procedure.getRef();
} else if(symbol instanceof ConstantVar) {
return ((ConstantVar) symbol).getRef();
} else if(symbol == null) {
// Either forward reference or a non-existing variable. Create a forward reference for later resolving.
return new ForwardVariableRef(ctx.NAME().getText());

View File

@ -42,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 EnumDefinition) continue;
if(tableSymbol instanceof TypeDefsScope) continue;
if(tableSymbol.getType() instanceof SymbolTypeStruct) continue;
Symbol codeSymbol = null;

View File

@ -6,6 +6,7 @@ import dk.camelot64.kickc.model.StructUnwinding;
import dk.camelot64.kickc.model.VariableReferenceInfos;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.ConstantVar;
import dk.camelot64.kickc.model.symbols.EnumDefinition;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
@ -129,12 +130,14 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization {
Collection<ConstantVar> allConstants = getScope().getAllConstants(true);
for(ConstantVar constant : allConstants) {
if(referenceInfos.isUnused(constant.getRef())) {
if(pass2 || getLog().isVerbosePass1CreateSsa()) {
getLog().append("Eliminating unused constant " + constant.toString(getProgram()));
if(!(constant.getScope() instanceof EnumDefinition)) {
if(referenceInfos.isUnused(constant.getRef())) {
if(pass2 || getLog().isVerbosePass1CreateSsa()) {
getLog().append("Eliminating unused constant " + constant.toString(getProgram()));
}
constant.getScope().remove(constant);
modified = true;
}
constant.getScope().remove(constant);
modified = true;
}
}

View File

@ -35,6 +35,28 @@ public class TestPrograms {
public TestPrograms() {
}
/* Awaiting better constant expression handling
@Test
public void testEnum3() throws IOException, URISyntaxException {
compileAndCompare("enum-3");
}
*/
@Test
public void testEnum2() throws IOException, URISyntaxException {
compileAndCompare("enum-2");
}
@Test
public void testEnum1() throws IOException, URISyntaxException {
compileAndCompare("enum-1");
}
@Test
public void testEnum0() throws IOException, URISyntaxException {
compileAndCompare("enum-0");
}
@Test
public void testTypedef1() throws IOException, URISyntaxException {
compileAndCompare("typedef-1");

9
src/test/kc/enum-0.kc Normal file
View File

@ -0,0 +1,9 @@
// Test of simple enum - two-value enum
enum State { OFF , ON };
void main() {
enum State state = ON;
const byte* SCREEN = 0x0400;
*SCREEN = state;
}

13
src/test/kc/enum-1.kc Normal file
View File

@ -0,0 +1,13 @@
// Test of simple enum - three-value enum with specified integer values and increment
enum State {
OFF,
ON=8,
BROKEN
};
void main() {
enum State state = BROKEN;
const byte* SCREEN = 0x0400;
*SCREEN = state;
}

13
src/test/kc/enum-2.kc Normal file
View File

@ -0,0 +1,13 @@
// Test of simple enum - char values with increment
enum Letter {
A = 'a',
B = 'b',
C
};
void main() {
enum Letter letter = B;
const byte* SCREEN = 0x0400;
*SCREEN = letter;
}

13
src/test/kc/enum-3.kc Normal file
View File

@ -0,0 +1,13 @@
// Test of simple enum - value with complex calculation
enum State {
OFF,
ON=4*4+2,
BROKEN
};
void main() {
enum State state = BROKEN;
const byte* SCREEN = 0x0400;
*SCREEN = state;
}

11
src/test/ref/enum-0.asm Normal file
View File

@ -0,0 +1,11 @@
// Test of simple enum - two-value enum
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const ON = 1
main: {
.label SCREEN = $400
lda #ON
sta SCREEN
rts
}

15
src/test/ref/enum-0.cfg Normal file
View File

@ -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) ON
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return

230
src/test/ref/enum-0.log Normal file
View File

@ -0,0 +1,230 @@
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
Identified constant variable (byte) main::state
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @1
(byte) main::state#0 ← (const byte) ON
(byte*) main::SCREEN#0 ← ((byte*)) (number) $400
*((byte*) main::SCREEN#0) ← (byte) main::state#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) ON = (byte) 1
(const byte) State::OFF = (byte) 0
(const byte) State::ON = (byte) 1
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(byte*) main::SCREEN#0
(byte) main::state
(byte) main::state#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::state#0 = ON
Constant (const byte*) main::SCREEN#0 = (byte*) 1024
Successful SSA optimization Pass2ConstantIdentification
Constant inlined main::state#0 = (const byte) ON
Successful SSA optimization Pass2ConstantInlining
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) ON
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte*) main::SCREEN
(byte) main::state
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
//SEG0 File Comments
// Test of simple enum - two-value enum
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const ON = 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: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) ON -- _deref_pbuc1=vbuc2
lda #ON
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) ON [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [State]
Uplift Scope [main]
Uplift Scope []
Uplifting [State] best 27 combination
Uplifting [main] best 27 combination
Uplifting [] best 27 combination
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Test of simple enum - two-value enum
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const ON = 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: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) ON -- _deref_pbuc1=vbuc2
lda #ON
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
(const byte) ON ON = (byte) 1
(const byte) State::OFF OFF = (byte) 0
(const byte) State::ON ON = (byte) 1
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
(byte) main::state
FINAL ASSEMBLER
Score: 12
//SEG0 File Comments
// Test of simple enum - two-value enum
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const ON = 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: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) ON -- _deref_pbuc1=vbuc2
lda #ON
sta SCREEN
//SEG11 main::@return
//SEG12 [5] return
rts
}

12
src/test/ref/enum-0.sym Normal file
View File

@ -0,0 +1,12 @@
(label) @1
(label) @begin
(label) @end
(const byte) ON ON = (byte) 1
(const byte) State::OFF OFF = (byte) 0
(const byte) State::ON ON = (byte) 1
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
(byte) main::state

11
src/test/ref/enum-1.asm Normal file
View File

@ -0,0 +1,11 @@
// Test of simple enum - three-value enum with specified integer values and increment
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const BROKEN = 9
main: {
.label SCREEN = $400
lda #BROKEN
sta SCREEN
rts
}

15
src/test/ref/enum-1.cfg Normal file
View File

@ -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) BROKEN
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return

232
src/test/ref/enum-1.log Normal file
View File

@ -0,0 +1,232 @@
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
Identified constant variable (byte) main::state
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @1
(byte) main::state#0 ← (const byte) BROKEN
(byte*) main::SCREEN#0 ← ((byte*)) (number) $400
*((byte*) main::SCREEN#0) ← (byte) main::state#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) BROKEN = (byte) 9
(const byte) State::BROKEN = (byte) 9
(const byte) State::OFF = (byte) 0
(const byte) State::ON = (number) 8
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(byte*) main::SCREEN#0
(byte) main::state
(byte) main::state#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::state#0 = BROKEN
Constant (const byte*) main::SCREEN#0 = (byte*) 1024
Successful SSA optimization Pass2ConstantIdentification
Constant inlined main::state#0 = (const byte) BROKEN
Successful SSA optimization Pass2ConstantInlining
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) BROKEN
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte*) main::SCREEN
(byte) main::state
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
//SEG0 File Comments
// Test of simple enum - three-value enum with specified integer values and increment
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const BROKEN = 9
//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: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) BROKEN -- _deref_pbuc1=vbuc2
lda #BROKEN
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) BROKEN [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [State]
Uplift Scope [main]
Uplift Scope []
Uplifting [State] best 27 combination
Uplifting [main] best 27 combination
Uplifting [] best 27 combination
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Test of simple enum - three-value enum with specified integer values and increment
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const BROKEN = 9
//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: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) BROKEN -- _deref_pbuc1=vbuc2
lda #BROKEN
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
(const byte) BROKEN BROKEN = (byte) 9
(const byte) State::BROKEN BROKEN = (byte) 9
(const byte) State::OFF OFF = (byte) 0
(const byte) State::ON ON = (number) 8
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
(byte) main::state
FINAL ASSEMBLER
Score: 12
//SEG0 File Comments
// Test of simple enum - three-value enum with specified integer values and increment
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const BROKEN = 9
//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: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) BROKEN -- _deref_pbuc1=vbuc2
lda #BROKEN
sta SCREEN
//SEG11 main::@return
//SEG12 [5] return
rts
}

13
src/test/ref/enum-1.sym Normal file
View File

@ -0,0 +1,13 @@
(label) @1
(label) @begin
(label) @end
(const byte) BROKEN BROKEN = (byte) 9
(const byte) State::BROKEN BROKEN = (byte) 9
(const byte) State::OFF OFF = (byte) 0
(const byte) State::ON ON = (number) 8
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
(byte) main::state

11
src/test/ref/enum-2.asm Normal file
View File

@ -0,0 +1,11 @@
// Test of simple enum - char values with increment
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const B = 'b'
main: {
.label SCREEN = $400
lda #B
sta SCREEN
rts
}

15
src/test/ref/enum-2.cfg Normal file
View File

@ -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) B
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return

232
src/test/ref/enum-2.log Normal file
View File

@ -0,0 +1,232 @@
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
Identified constant variable (byte) main::letter
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @1
(byte) main::letter#0 ← (const byte) B
(byte*) main::SCREEN#0 ← ((byte*)) (number) $400
*((byte*) main::SCREEN#0) ← (byte) main::letter#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) B = (byte) 'b'
(const byte) Letter::A = (byte) 'a'
(const byte) Letter::B = (byte) 'b'
(const byte) Letter::C = (byte) 'b'+(byte) 1
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(byte*) main::SCREEN#0
(byte) main::letter
(byte) main::letter#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::letter#0 = B
Constant (const byte*) main::SCREEN#0 = (byte*) 1024
Successful SSA optimization Pass2ConstantIdentification
Constant inlined main::letter#0 = (const byte) B
Successful SSA optimization Pass2ConstantInlining
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) B
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte*) main::SCREEN
(byte) main::letter
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
//SEG0 File Comments
// Test of simple enum - char values with increment
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const B = 'b'
//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: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) B -- _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) B [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [Letter]
Uplift Scope [main]
Uplift Scope []
Uplifting [Letter] best 27 combination
Uplifting [main] best 27 combination
Uplifting [] best 27 combination
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Test of simple enum - char values with increment
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const B = 'b'
//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: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) B -- _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
(const byte) B B = (byte) 'b'
(const byte) Letter::A A = (byte) 'a'
(const byte) Letter::B B = (byte) 'b'
(const byte) Letter::C C = (byte) 'b'+(byte) 1
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
(byte) main::letter
FINAL ASSEMBLER
Score: 12
//SEG0 File Comments
// Test of simple enum - char values with increment
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const B = 'b'
//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: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) B -- _deref_pbuc1=vbuc2
lda #B
sta SCREEN
//SEG11 main::@return
//SEG12 [5] return
rts
}

13
src/test/ref/enum-2.sym Normal file
View File

@ -0,0 +1,13 @@
(label) @1
(label) @begin
(label) @end
(const byte) B B = (byte) 'b'
(const byte) Letter::A A = (byte) 'a'
(const byte) Letter::B B = (byte) 'b'
(const byte) Letter::C C = (byte) 'b'+(byte) 1
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
(byte) main::letter