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:
parent
e4af001041
commit
10082a5d96
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -301,6 +301,11 @@ public abstract class Scope implements Symbol {
|
|||||||
return (StructDefinition) getSymbol(name);
|
return (StructDefinition) getSymbol(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EnumDefinition getEnumDefinition(String name) {
|
||||||
|
return (EnumDefinition) getSymbol(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Scope getScope(ScopeRef scopeRef) {
|
public Scope getScope(ScopeRef scopeRef) {
|
||||||
if(scopeRef.getFullName().equals("") && this instanceof ProgramScope) {
|
if(scopeRef.getFullName().equals("") && this instanceof ProgramScope) {
|
||||||
// Special case for the outer program scope
|
// Special case for the outer program scope
|
||||||
|
@ -51,6 +51,6 @@ public class StructDefinition extends Scope {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(Program program) {
|
public String toString(Program program) {
|
||||||
return "block-"+getFullName();
|
return "struct-"+getFullName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -146,7 +146,7 @@ enumRef
|
|||||||
;
|
;
|
||||||
|
|
||||||
enumDef
|
enumDef
|
||||||
: 'enum' NAME '{' enumMemberList '}'
|
: 'enum' NAME? '{' enumMemberList '}'
|
||||||
;
|
;
|
||||||
|
|
||||||
enumMemberList
|
enumMemberList
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -4,11 +4,7 @@ import dk.camelot64.kickc.Compiler;
|
|||||||
import dk.camelot64.kickc.NumberParser;
|
import dk.camelot64.kickc.NumberParser;
|
||||||
import dk.camelot64.kickc.asm.AsmClobber;
|
import dk.camelot64.kickc.asm.AsmClobber;
|
||||||
import dk.camelot64.kickc.model.*;
|
import dk.camelot64.kickc.model.*;
|
||||||
import dk.camelot64.kickc.model.InternalError;
|
import dk.camelot64.kickc.model.operators.*;
|
||||||
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.statements.*;
|
import dk.camelot64.kickc.model.statements.*;
|
||||||
import dk.camelot64.kickc.model.symbols.*;
|
import dk.camelot64.kickc.model.symbols.*;
|
||||||
import dk.camelot64.kickc.model.types.*;
|
import dk.camelot64.kickc.model.types.*;
|
||||||
@ -522,9 +518,6 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
// Add comments to constant
|
// Add comments to constant
|
||||||
lValue.setComments(ensureUnusedComments(comments));
|
lValue.setComments(ensureUnusedComments(comments));
|
||||||
}
|
}
|
||||||
//if(type instanceof SymbolTypeStruct) {
|
|
||||||
// lValue.setDeclaredVolatile(true);
|
|
||||||
//}
|
|
||||||
KickCParser.ExprContext initializer = ctx.expr();
|
KickCParser.ExprContext initializer = ctx.expr();
|
||||||
if(declVarStructMember || declVarTypeDef) {
|
if(declVarStructMember || declVarTypeDef) {
|
||||||
if(initializer != null) {
|
if(initializer != null) {
|
||||||
@ -1205,6 +1198,80 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
return structDefinition.getType();
|
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
|
@Override
|
||||||
public Object visitTypeNamedRef(KickCParser.TypeNamedRefContext ctx) {
|
public Object visitTypeNamedRef(KickCParser.TypeNamedRefContext ctx) {
|
||||||
Scope typeDefScope = program.getScope().getTypeDefScope();
|
Scope typeDefScope = program.getScope().getTypeDefScope();
|
||||||
@ -1494,11 +1561,15 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
RValue right = (RValue) this.visit(ctx.expr(1));
|
RValue right = (RValue) this.visit(ctx.expr(1));
|
||||||
String op = ((TerminalNode) ctx.getChild(1)).getSymbol().getText();
|
String op = ((TerminalNode) ctx.getChild(1)).getSymbol().getText();
|
||||||
Operator operator = Operators.getBinary(op);
|
Operator operator = Operators.getBinary(op);
|
||||||
VariableIntermediate tmpVar = getCurrentScope().addVariableIntermediate();
|
// if(left instanceof ConstantValue && right instanceof ConstantValue) {
|
||||||
VariableRef tmpVarRef = tmpVar.getRef();
|
// return new ConstantBinary((ConstantValue) left, (OperatorBinary) operator, (ConstantValue) right);
|
||||||
Statement stmt = new StatementAssignment(tmpVarRef, left, operator, right, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx)));
|
// } else {
|
||||||
sequence.addStatement(stmt);
|
VariableIntermediate tmpVar = getCurrentScope().addVariableIntermediate();
|
||||||
return tmpVarRef;
|
VariableRef tmpVarRef = tmpVar.getRef();
|
||||||
|
Statement stmt = new StatementAssignment(tmpVarRef, left, operator, right, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx)));
|
||||||
|
sequence.addStatement(stmt);
|
||||||
|
return tmpVarRef;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1515,6 +1586,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
// Special handling of negative literal number
|
// Special handling of negative literal number
|
||||||
if(child instanceof ConstantInteger && operator.equals(Operators.NEG)) {
|
if(child instanceof ConstantInteger && operator.equals(Operators.NEG)) {
|
||||||
return new ConstantInteger(-((ConstantInteger) child).getInteger(), ((ConstantInteger) child).getType());
|
return new ConstantInteger(-((ConstantInteger) child).getInteger(), ((ConstantInteger) child).getType());
|
||||||
|
// } else if(child instanceof ConstantValue) {
|
||||||
|
// return new ConstantUnary((OperatorUnary) operator, (ConstantValue) child);
|
||||||
} else {
|
} else {
|
||||||
VariableIntermediate tmpVar = getCurrentScope().addVariableIntermediate();
|
VariableIntermediate tmpVar = getCurrentScope().addVariableIntermediate();
|
||||||
VariableRef tmpVarRef = tmpVar.getRef();
|
VariableRef tmpVarRef = tmpVar.getRef();
|
||||||
@ -1588,6 +1661,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
} else if(symbol instanceof Procedure) {
|
} else if(symbol instanceof Procedure) {
|
||||||
Procedure procedure = (Procedure) symbol;
|
Procedure procedure = (Procedure) symbol;
|
||||||
return procedure.getRef();
|
return procedure.getRef();
|
||||||
|
} else if(symbol instanceof ConstantVar) {
|
||||||
|
return ((ConstantVar) symbol).getRef();
|
||||||
} else if(symbol == null) {
|
} else if(symbol == null) {
|
||||||
// Either forward reference or a non-existing variable. Create a forward reference for later resolving.
|
// Either forward reference or a non-existing variable. Create a forward reference for later resolving.
|
||||||
return new ForwardVariableRef(ctx.NAME().getText());
|
return new ForwardVariableRef(ctx.NAME().getText());
|
||||||
|
@ -42,6 +42,7 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
|
|||||||
if(tableSymbol instanceof VariableUnversioned) continue;
|
if(tableSymbol instanceof VariableUnversioned) continue;
|
||||||
if(tableSymbol instanceof ConstantVar) continue;
|
if(tableSymbol instanceof ConstantVar) continue;
|
||||||
if(tableSymbol instanceof StructDefinition) continue;
|
if(tableSymbol instanceof StructDefinition) continue;
|
||||||
|
if(tableSymbol instanceof EnumDefinition) continue;
|
||||||
if(tableSymbol instanceof TypeDefsScope) continue;
|
if(tableSymbol instanceof TypeDefsScope) continue;
|
||||||
if(tableSymbol.getType() instanceof SymbolTypeStruct) continue;
|
if(tableSymbol.getType() instanceof SymbolTypeStruct) continue;
|
||||||
Symbol codeSymbol = null;
|
Symbol codeSymbol = null;
|
||||||
|
@ -6,6 +6,7 @@ import dk.camelot64.kickc.model.StructUnwinding;
|
|||||||
import dk.camelot64.kickc.model.VariableReferenceInfos;
|
import dk.camelot64.kickc.model.VariableReferenceInfos;
|
||||||
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.ConstantVar;
|
||||||
|
import dk.camelot64.kickc.model.symbols.EnumDefinition;
|
||||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||||
import dk.camelot64.kickc.model.symbols.Variable;
|
import dk.camelot64.kickc.model.symbols.Variable;
|
||||||
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||||
@ -129,12 +130,14 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization {
|
|||||||
|
|
||||||
Collection<ConstantVar> allConstants = getScope().getAllConstants(true);
|
Collection<ConstantVar> allConstants = getScope().getAllConstants(true);
|
||||||
for(ConstantVar constant : allConstants) {
|
for(ConstantVar constant : allConstants) {
|
||||||
if(referenceInfos.isUnused(constant.getRef())) {
|
if(!(constant.getScope() instanceof EnumDefinition)) {
|
||||||
if(pass2 || getLog().isVerbosePass1CreateSsa()) {
|
if(referenceInfos.isUnused(constant.getRef())) {
|
||||||
getLog().append("Eliminating unused constant " + constant.toString(getProgram()));
|
if(pass2 || getLog().isVerbosePass1CreateSsa()) {
|
||||||
|
getLog().append("Eliminating unused constant " + constant.toString(getProgram()));
|
||||||
|
}
|
||||||
|
constant.getScope().remove(constant);
|
||||||
|
modified = true;
|
||||||
}
|
}
|
||||||
constant.getScope().remove(constant);
|
|
||||||
modified = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,28 @@ public class TestPrograms {
|
|||||||
public 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
|
@Test
|
||||||
public void testTypedef1() throws IOException, URISyntaxException {
|
public void testTypedef1() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("typedef-1");
|
compileAndCompare("typedef-1");
|
||||||
|
9
src/test/kc/enum-0.kc
Normal file
9
src/test/kc/enum-0.kc
Normal 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
13
src/test/kc/enum-1.kc
Normal 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
13
src/test/kc/enum-2.kc
Normal 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
13
src/test/kc/enum-3.kc
Normal 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
11
src/test/ref/enum-0.asm
Normal 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
15
src/test/ref/enum-0.cfg
Normal 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
230
src/test/ref/enum-0.log
Normal 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
12
src/test/ref/enum-0.sym
Normal 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
11
src/test/ref/enum-1.asm
Normal 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
15
src/test/ref/enum-1.cfg
Normal 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
232
src/test/ref/enum-1.log
Normal 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
13
src/test/ref/enum-1.sym
Normal 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
11
src/test/ref/enum-2.asm
Normal 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
15
src/test/ref/enum-2.cfg
Normal 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
232
src/test/ref/enum-2.log
Normal 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
13
src/test/ref/enum-2.sym
Normal 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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user