1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-03-24 15:32:58 +00:00

Added support for comma-separated variable declarations in for()-loop init. Closes #159

This commit is contained in:
jespergravgaard 2019-04-16 00:22:47 +02:00
parent 24ca7e9c68
commit f41744cd96
13 changed files with 1453 additions and 1009 deletions

View File

@ -22,13 +22,17 @@ declSeq
;
decl
: declVariable
: declVariables ';'
| declFunction
| declKasm
;
declVariable
: directive* typeDecl directive* declVariableList ';'
declTypes
: directive* typeDecl directive*
;
declVariables
: declTypes declVariableList
;
declVariableList
@ -41,14 +45,14 @@ declVariableInit
;
declFunction
: directive* typeDecl directive* NAME '(' parameterListDecl? ')' '{' stmtSeq? '}'
: declTypes NAME '(' parameterListDecl? ')' '{' stmtSeq? '}'
;
parameterListDecl
: parameterDecl (',' parameterDecl)* ;
parameterDecl
: directive* typeDecl directive* NAME #parameterDeclType
: declTypes NAME #parameterDeclType
| SIMPLETYPE #parameterDeclVoid
;
@ -67,13 +71,13 @@ stmtSeq
;
stmt
: declVariable #stmtDeclVar
: declVariables ';' #stmtDeclVar
| '{' stmtSeq? '}' #stmtBlock
| commaExpr ';' #stmtExpr
| 'if' '(' commaExpr ')' stmt ( 'else' stmt )? #stmtIfElse
| directive* 'while' '(' commaExpr ')' stmt #stmtWhile
| directive* 'do' stmt 'while' '(' commaExpr ')' ';' #stmtDoWhile
| directive* 'for' '(' forDeclaration? forIteration ')' stmt #stmtFor
| directive* 'for' '(' forLoop ')' stmt #stmtFor
| 'return' commaExpr? ';' #stmtReturn
| 'break' ';' #stmtBreak
| 'continue' ';' #stmtContinue
@ -81,13 +85,14 @@ stmt
| declKasm #stmtDeclKasm
;
forDeclaration
: directive* typeDecl? directive* NAME ('=' expr)? #forDecl
forLoop
: forClassicInit ';' commaExpr ';' commaExpr? #forClassic
| declTypes? NAME ':' expr ( '..' ) expr #forRange
;
forIteration
: ';' commaExpr ';' commaExpr? # forClassic
| ':' expr ( '..' ) expr #forRange
forClassicInit
: declVariables? #forClassicInitDecl
| commaExpr #forClassicInitExpr
;
typeDecl

View File

@ -88,13 +88,25 @@ public class KickCBaseListener implements KickCListener {
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterDeclVariable(KickCParser.DeclVariableContext ctx) { }
@Override public void enterDeclTypes(KickCParser.DeclTypesContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitDeclVariable(KickCParser.DeclVariableContext ctx) { }
@Override public void exitDeclTypes(KickCParser.DeclTypesContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterDeclVariables(KickCParser.DeclVariablesContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitDeclVariables(KickCParser.DeclVariablesContext ctx) { }
/**
* {@inheritDoc}
*
@ -407,18 +419,6 @@ public class KickCBaseListener implements KickCListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitStmtDeclKasm(KickCParser.StmtDeclKasmContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterForDecl(KickCParser.ForDeclContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitForDecl(KickCParser.ForDeclContext ctx) { }
/**
* {@inheritDoc}
*
@ -443,6 +443,30 @@ public class KickCBaseListener implements KickCListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitForRange(KickCParser.ForRangeContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterForClassicInitDecl(KickCParser.ForClassicInitDeclContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitForClassicInitDecl(KickCParser.ForClassicInitDeclContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterForClassicInitExpr(KickCParser.ForClassicInitExprContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitForClassicInitExpr(KickCParser.ForClassicInitExprContext ctx) { }
/**
* {@inheritDoc}
*

View File

@ -59,7 +59,14 @@ public class KickCBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDeclVariable(KickCParser.DeclVariableContext ctx) { return visitChildren(ctx); }
@Override public T visitDeclTypes(KickCParser.DeclTypesContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDeclVariables(KickCParser.DeclVariablesContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
@ -242,13 +249,6 @@ public class KickCBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitStmtDeclKasm(KickCParser.StmtDeclKasmContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitForDecl(KickCParser.ForDeclContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
@ -263,6 +263,20 @@ public class KickCBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitForRange(KickCParser.ForRangeContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitForClassicInitDecl(KickCParser.ForClassicInitDeclContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitForClassicInitExpr(KickCParser.ForClassicInitExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*

View File

@ -68,15 +68,25 @@ public interface KickCListener extends ParseTreeListener {
*/
void exitDecl(KickCParser.DeclContext ctx);
/**
* Enter a parse tree produced by {@link KickCParser#declVariable}.
* Enter a parse tree produced by {@link KickCParser#declTypes}.
* @param ctx the parse tree
*/
void enterDeclVariable(KickCParser.DeclVariableContext ctx);
void enterDeclTypes(KickCParser.DeclTypesContext ctx);
/**
* Exit a parse tree produced by {@link KickCParser#declVariable}.
* Exit a parse tree produced by {@link KickCParser#declTypes}.
* @param ctx the parse tree
*/
void exitDeclVariable(KickCParser.DeclVariableContext ctx);
void exitDeclTypes(KickCParser.DeclTypesContext ctx);
/**
* Enter a parse tree produced by {@link KickCParser#declVariables}.
* @param ctx the parse tree
*/
void enterDeclVariables(KickCParser.DeclVariablesContext ctx);
/**
* Exit a parse tree produced by {@link KickCParser#declVariables}.
* @param ctx the parse tree
*/
void exitDeclVariables(KickCParser.DeclVariablesContext ctx);
/**
* Enter a parse tree produced by {@link KickCParser#declVariableList}.
* @param ctx the parse tree
@ -379,42 +389,54 @@ public interface KickCListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitStmtDeclKasm(KickCParser.StmtDeclKasmContext ctx);
/**
* Enter a parse tree produced by the {@code forDecl}
* labeled alternative in {@link KickCParser#forDeclaration}.
* @param ctx the parse tree
*/
void enterForDecl(KickCParser.ForDeclContext ctx);
/**
* Exit a parse tree produced by the {@code forDecl}
* labeled alternative in {@link KickCParser#forDeclaration}.
* @param ctx the parse tree
*/
void exitForDecl(KickCParser.ForDeclContext ctx);
/**
* Enter a parse tree produced by the {@code forClassic}
* labeled alternative in {@link KickCParser#forIteration}.
* labeled alternative in {@link KickCParser#forLoop}.
* @param ctx the parse tree
*/
void enterForClassic(KickCParser.ForClassicContext ctx);
/**
* Exit a parse tree produced by the {@code forClassic}
* labeled alternative in {@link KickCParser#forIteration}.
* labeled alternative in {@link KickCParser#forLoop}.
* @param ctx the parse tree
*/
void exitForClassic(KickCParser.ForClassicContext ctx);
/**
* Enter a parse tree produced by the {@code forRange}
* labeled alternative in {@link KickCParser#forIteration}.
* labeled alternative in {@link KickCParser#forLoop}.
* @param ctx the parse tree
*/
void enterForRange(KickCParser.ForRangeContext ctx);
/**
* Exit a parse tree produced by the {@code forRange}
* labeled alternative in {@link KickCParser#forIteration}.
* labeled alternative in {@link KickCParser#forLoop}.
* @param ctx the parse tree
*/
void exitForRange(KickCParser.ForRangeContext ctx);
/**
* Enter a parse tree produced by the {@code forClassicInitDecl}
* labeled alternative in {@link KickCParser#forClassicInit}.
* @param ctx the parse tree
*/
void enterForClassicInitDecl(KickCParser.ForClassicInitDeclContext ctx);
/**
* Exit a parse tree produced by the {@code forClassicInitDecl}
* labeled alternative in {@link KickCParser#forClassicInit}.
* @param ctx the parse tree
*/
void exitForClassicInitDecl(KickCParser.ForClassicInitDeclContext ctx);
/**
* Enter a parse tree produced by the {@code forClassicInitExpr}
* labeled alternative in {@link KickCParser#forClassicInit}.
* @param ctx the parse tree
*/
void enterForClassicInitExpr(KickCParser.ForClassicInitExprContext ctx);
/**
* Exit a parse tree produced by the {@code forClassicInitExpr}
* labeled alternative in {@link KickCParser#forClassicInit}.
* @param ctx the parse tree
*/
void exitForClassicInitExpr(KickCParser.ForClassicInitExprContext ctx);
/**
* Enter a parse tree produced by the {@code typePar}
* labeled alternative in {@link KickCParser#typeDecl}.

File diff suppressed because it is too large Load Diff

View File

@ -47,11 +47,17 @@ public interface KickCVisitor<T> extends ParseTreeVisitor<T> {
*/
T visitDecl(KickCParser.DeclContext ctx);
/**
* Visit a parse tree produced by {@link KickCParser#declVariable}.
* Visit a parse tree produced by {@link KickCParser#declTypes}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitDeclVariable(KickCParser.DeclVariableContext ctx);
T visitDeclTypes(KickCParser.DeclTypesContext ctx);
/**
* Visit a parse tree produced by {@link KickCParser#declVariables}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitDeclVariables(KickCParser.DeclVariablesContext ctx);
/**
* Visit a parse tree produced by {@link KickCParser#declVariableList}.
* @param ctx the parse tree
@ -229,27 +235,34 @@ public interface KickCVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitStmtDeclKasm(KickCParser.StmtDeclKasmContext ctx);
/**
* Visit a parse tree produced by the {@code forDecl}
* labeled alternative in {@link KickCParser#forDeclaration}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitForDecl(KickCParser.ForDeclContext ctx);
/**
* Visit a parse tree produced by the {@code forClassic}
* labeled alternative in {@link KickCParser#forIteration}.
* labeled alternative in {@link KickCParser#forLoop}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitForClassic(KickCParser.ForClassicContext ctx);
/**
* Visit a parse tree produced by the {@code forRange}
* labeled alternative in {@link KickCParser#forIteration}.
* labeled alternative in {@link KickCParser#forLoop}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitForRange(KickCParser.ForRangeContext ctx);
/**
* Visit a parse tree produced by the {@code forClassicInitDecl}
* labeled alternative in {@link KickCParser#forClassicInit}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitForClassicInitDecl(KickCParser.ForClassicInitDeclContext ctx);
/**
* Visit a parse tree produced by the {@code forClassicInitExpr}
* labeled alternative in {@link KickCParser#forClassicInit}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitForClassicInitExpr(KickCParser.ForClassicInitExprContext ctx);
/**
* Visit a parse tree produced by the {@code typePar}
* labeled alternative in {@link KickCParser#typeDecl}.

View File

@ -111,10 +111,13 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
@Override
public Object visitDeclFunction(KickCParser.DeclFunctionContext ctx) {
SymbolType type = (SymbolType) visit(ctx.typeDecl());
this.visitDeclTypes(ctx.declTypes());
SymbolType type = declVarType;
List<Directive> directives = declVarDirectives;
String name = ctx.NAME().getText();
Procedure procedure = getCurrentScope().addProcedure(name, type);
addDirectives(procedure, ctx.directive());
addDirectives(procedure, directives, new StatementSource(ctx));
procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx)));
scopeStack.push(procedure);
Label procExit = procedure.addLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
@ -142,6 +145,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
sequence.addStatement(new StatementReturn(returnVarRef, new StatementSource(ctx), Comment.NO_COMMENTS));
scopeStack.pop();
sequence.addStatement(new StatementProcedureEnd(procedure.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
exitDeclTypes();
return null;
}
@ -169,11 +173,13 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
@Override
public Object visitParameterDeclType(KickCParser.ParameterDeclTypeContext ctx) {
SymbolType type = (SymbolType) this.visit(ctx.typeDecl());
this.visitDeclTypes(ctx.declTypes());
SymbolType type = declVarType;
List<Directive> directives = declVarDirectives;
VariableUnversioned param = new VariableUnversioned(ctx.NAME().getText(), getCurrentScope(), type);
// Add directives
List<Directive> directives = getDirectives(ctx.directive());
addDirectives(param, type, directives, new StatementSource(ctx));
exitDeclTypes();
return param;
}
@ -415,16 +421,34 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
/** Holds the declared comments when descending into a Variable Declaration. */
private List<Comment> declVarComments = null;
/**
* Visit the type/directive part of a declaration. Setup the local decl-variables
* @param ctx The declaration type & directives
* @return null
*/
@Override
public Object visitDeclVariable(KickCParser.DeclVariableContext ctx) {
public Object visitDeclTypes(KickCParser.DeclTypesContext ctx) {
List<KickCParser.DirectiveContext> directive = ctx.directive();
this.declVarType = (SymbolType) visit(ctx.typeDecl());
this.declVarDirectives = getDirectives(directive);
this.declVarComments = getCommentsSymbol(ctx);
this.visit(ctx.declVariableList());
this.declVarComments = getCommentsSymbol(ctx.getParent());
return null;
}
/**
* Clear the local decl-variables
*/
private void exitDeclTypes() {
this.declVarType = null;
this.declVarDirectives = null;
this.declVarComments = null;
}
@Override
public Object visitDeclVariables(KickCParser.DeclVariablesContext ctx) {
this.visit(ctx.declTypes());
this.visit(ctx.declVariableList());
exitDeclTypes();
return null;
}
@ -489,9 +513,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
}
}
return null;
}
/**
@ -542,12 +564,10 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
* Add declared directives to a procedure.
*
* @param procedure The procedure
* @param directivesCtx The directives to add
* @param directives The directives to add
*/
private void addDirectives(Procedure procedure, List<KickCParser.DirectiveContext> directivesCtx) {
List<Directive> directives = getDirectives(directivesCtx);
private void addDirectives(Procedure procedure, List<Directive> directives, StatementSource source) {
for(Directive directive : directives) {
StatementSource source = new StatementSource(directivesCtx.get(0));
if(directive instanceof DirectiveInline) {
procedure.setDeclaredInline(true);
} else if(directive instanceof DirectiveInterrupt) {
@ -787,30 +807,17 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
@Override
public Object visitStmtFor(KickCParser.StmtForContext ctx) {
this.visit(ctx.forIteration());
this.visit(ctx.forLoop());
return null;
}
@Override
public Object visitForDecl(KickCParser.ForDeclContext ctx) {
return super.visitForDecl(ctx);
}
@Override
public Object visitForClassic(KickCParser.ForClassicContext ctx) {
BlockScope blockScope = getCurrentScope().addBlockScope();
scopeStack.push(blockScope);
loopStack.push(new Loop(blockScope));
this.visit(ctx.forClassicInit());
KickCParser.StmtForContext stmtForCtx = (KickCParser.StmtForContext) ctx.getParent();
KickCParser.ForDeclContext forDeclCtx = (KickCParser.ForDeclContext) stmtForCtx.forDeclaration();
if(forDeclCtx!=null) {
// Create and assign declared loop variable
Variable lValue = getForVariable(forDeclCtx);
KickCParser.ExprContext initializer = forDeclCtx.expr();
if(initializer != null) {
addInitialAssignment(initializer, lValue, Comment.NO_COMMENTS);
}
}
// Add label
Label repeatLabel = getCurrentScope().addLabelIntermediate();
List<Comment> comments = getCommentsSymbol(stmtForCtx);
@ -838,18 +845,41 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
return null;
}
@Override
public Object visitForClassicInitDecl(KickCParser.ForClassicInitDeclContext ctx) {
if(ctx.declVariables()!=null) {
this.visit(ctx.declVariables());
}
return null;
}
@Override
public Object visitForRange(KickCParser.ForRangeContext ctx) {
BlockScope blockScope = getCurrentScope().addBlockScope();
scopeStack.push(blockScope);
loopStack.push(new Loop(blockScope));
KickCParser.StmtForContext stmtForCtx = (KickCParser.StmtForContext) ctx.getParent();
KickCParser.ForDeclContext forDeclCtx = (KickCParser.ForDeclContext) stmtForCtx.forDeclaration();
if(forDeclCtx==null) {
throw new CompileError("Ranged for() must have iteration variable.", new StatementSource(ctx));
// Create / find declared loop variable
if(ctx.declTypes()!=null) {
this.visitDeclTypes(ctx.declTypes());
}
// Create declared loop variable
Variable lValue = getForVariable(forDeclCtx);
SymbolType varType = declVarType;
List<Directive> varDirectives = declVarDirectives;
String varName = ctx.NAME().getText();
Variable lValue;
if(varType != null) {
try {
lValue = getCurrentScope().addVariable(varName, varType);
} catch(CompileError e) {
throw new CompileError(e.getMessage(), new StatementSource(ctx));
}
// Add directives
addDirectives(lValue, varType, varDirectives, new StatementSource(ctx));
} else {
lValue = getCurrentScope().getVariable(varName);
}
exitDeclTypes();
KickCParser.StmtForContext stmtForCtx = (KickCParser.StmtForContext) ctx.getParent();
KickCParser.ExprContext rangeFirstCtx = ctx.expr(0);
KickCParser.ExprContext rangeLastCtx = ctx.expr(1);
// Assign loop variable with first value
@ -911,34 +941,6 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
}
}
/**
* Get the variable of a for-loop.
*
* @param forDeclCtx The variable declaration
* @return The variable of the for loop
*/
private Variable getForVariable(KickCParser.ForDeclContext forDeclCtx) {
String varName = forDeclCtx.NAME().getText();
Variable lValue;
if(forDeclCtx.typeDecl() != null) {
SymbolType type = (SymbolType) visit(forDeclCtx.typeDecl());
try {
lValue = getCurrentScope().addVariable(varName, type);
} catch(CompileError e) {
throw new CompileError(e.getMessage(), new StatementSource(forDeclCtx));
}
// Add directives
List<Directive> directives = getDirectives(forDeclCtx.directive());
addDirectives(lValue, type, directives, new StatementSource(forDeclCtx));
} else {
lValue = getCurrentScope().getVariable(varName);
}
if(lValue == null) {
throw new CompileError("Unknown variable! " + varName, new StatementSource(forDeclCtx));
}
return lValue;
}
@Override
public Object visitStmtBreak(KickCParser.StmtBreakContext ctx) {
if(loopStack.isEmpty()) {

View File

@ -37,6 +37,11 @@ public class TestPrograms {
// compileAndCompare("pointer-cast-3");
//}
@Test
public void testCommaDeclFor() throws IOException, URISyntaxException {
compileAndCompare("comma-decl-for");
}
@Test
public void testCommaDecl() throws IOException, URISyntaxException {
compileAndCompare("comma-decl");
@ -59,7 +64,7 @@ public class TestPrograms {
@Test
public void testForRangedNoVar() throws IOException, URISyntaxException {
assertError("for-ranged-novar", "Ranged for() must have iteration variable");
assertError("for-ranged-novar", "extraneous input");
}
@Test

View File

@ -0,0 +1,8 @@
// Tests comma-separated declarations inside for()
void main() {
const byte* SCREEN = $400;
for(byte i, j='g'; i<10; i++, j++) {
SCREEN[i] = j;
}
}

View File

@ -0,0 +1,17 @@
// Tests comma-separated declarations inside for()
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label SCREEN = $400
ldx #0
lda #'g'
b1:
sta SCREEN,x
inx
clc
adc #1
cpx #$a
bcc b1
rts
}

View File

@ -0,0 +1,23 @@
@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] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@1/(byte) main::i#1 )
[5] (byte) main::j#2 ← phi( main/(byte) 'g' main::@1/(byte) main::j#1 )
[6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) main::j#2
[7] (byte) main::i#1 ← ++ (byte) main::i#2
[8] (byte) main::j#1 ← ++ (byte) main::j#2
[9] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $a) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[10] return
to:@return

View File

@ -0,0 +1,347 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @1
(byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
(byte) main::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
(byte) main::j#0 ← (byte) 'g'
to:main::@1
main::@1: scope:[main] from main main::@1
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(byte) main::j#2 ← phi( main/(byte) main::j#0 main::@1/(byte) main::j#1 )
*((byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) main::j#2
(byte) main::i#1 ← ++ (byte) main::i#2
(byte) main::j#1 ← ++ (byte) main::j#2
(bool~) main::$0 ← (byte) main::i#1 < (byte/signed byte/word/signed word/dword/signed dword) $a
if((bool~) main::$0) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
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()
(bool~) main::$0
(label) main::@1
(label) main::@return
(byte*) main::SCREEN
(byte*) main::SCREEN#0
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::j
(byte) main::j#0
(byte) main::j#1
(byte) main::j#2
Culled Empty Block (label) @2
Successful SSA optimization Pass2CullEmptyBlocks
Simple Condition (bool~) main::$0 [8] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $a) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte*) main::SCREEN#0 = ((byte*))$400
Constant (const byte) main::i#0 = 0
Constant (const byte) main::j#0 = 'g'
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with var siblings (const byte) main::i#0
Inlining constant with var siblings (const byte) main::j#0
Constant inlined main::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0
Constant inlined main::j#0 = (byte) 'g'
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@3(between main::@1 and main::@1)
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
CALL GRAPH
Calls in [] to main:2
Created 2 initial phi equivalence classes
Coalesced [11] main::j#3 ← main::j#1
Coalesced [12] main::i#3 ← main::i#1
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) main::@3
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
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] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@1/(byte) main::i#1 )
[5] (byte) main::j#2 ← phi( main/(byte) 'g' main::@1/(byte) main::j#1 )
[6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) main::j#2
[7] (byte) main::i#1 ← ++ (byte) main::i#2
[8] (byte) main::j#1 ← ++ (byte) main::j#2
[9] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $a) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[10] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte*) main::SCREEN
(byte) main::i
(byte) main::i#1 11.0
(byte) main::i#2 16.5
(byte) main::j
(byte) main::j#1 11.0
(byte) main::j#2 11.0
Initial phi equivalence classes
[ main::j#2 main::j#1 ]
[ main::i#2 main::i#1 ]
Complete equivalence classes
[ main::j#2 main::j#1 ]
[ main::i#2 main::i#1 ]
Allocated zp ZP_BYTE:2 [ main::j#2 main::j#1 ]
Allocated zp ZP_BYTE:3 [ main::i#2 main::i#1 ]
INITIAL ASM
//SEG0 File Comments
// Tests comma-separated declarations inside for()
//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
//SEG7 [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG9 @end
bend:
//SEG10 main
main: {
.label SCREEN = $400
.label i = 3
.label j = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
//SEG13 [5] phi (byte) main::j#2 = (byte) 'g' [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #'g'
sta j
jmp b1
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
jmp b1
//SEG17 main::@1
b1:
//SEG18 [6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) main::j#2 -- pbuc1_derefidx_vbuz1=vbuz2
lda j
ldy i
sta SCREEN,y
//SEG19 [7] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG20 [8] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuz1=_inc_vbuz1
inc j
//SEG21 [9] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $a) goto main::@1 -- vbuz1_lt_vbuc1_then_la1
lda i
cmp #$a
bcc b1_from_b1
jmp breturn
//SEG22 main::@return
breturn:
//SEG23 [10] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Potential registers zp ZP_BYTE:2 [ main::j#2 main::j#1 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:3 [ main::i#2 main::i#1 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 27.5: zp ZP_BYTE:3 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:2 [ main::j#2 main::j#1 ]
Uplift Scope []
Uplifting [main] best 303 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::j#2 main::j#1 ]
Uplifting [] best 303 combination
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests comma-separated declarations inside for()
//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
//SEG7 [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG9 @end
bend:
//SEG10 main
main: {
.label SCREEN = $400
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG13 [5] phi (byte) main::j#2 = (byte) 'g' [phi:main->main::@1#1] -- vbuaa=vbuc1
lda #'g'
jmp b1
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
jmp b1
//SEG17 main::@1
b1:
//SEG18 [6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) main::j#2 -- pbuc1_derefidx_vbuxx=vbuaa
sta SCREEN,x
//SEG19 [7] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG20 [8] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuaa=_inc_vbuaa
clc
adc #1
//SEG21 [9] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $a) goto main::@1 -- vbuxx_lt_vbuc1_then_la1
cpx #$a
bcc b1_from_b1
jmp breturn
//SEG22 main::@return
breturn:
//SEG23 [10] return
rts
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label b1_from_b1 with b1
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@1
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(byte) main::i
(byte) main::i#1 reg byte x 11.0
(byte) main::i#2 reg byte x 16.5
(byte) main::j
(byte) main::j#1 reg byte a 11.0
(byte) main::j#2 reg byte a 11.0
reg byte a [ main::j#2 main::j#1 ]
reg byte x [ main::i#2 main::i#1 ]
FINAL ASSEMBLER
Score: 201
//SEG0 File Comments
// Tests comma-separated declarations inside for()
//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 [4] phi from @1 to main [phi:@1->main]
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
//SEG9 @end
//SEG10 main
main: {
.label SCREEN = $400
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG13 [5] phi (byte) main::j#2 = (byte) 'g' [phi:main->main::@1#1] -- vbuaa=vbuc1
lda #'g'
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
//SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
//SEG17 main::@1
b1:
//SEG18 [6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) main::j#2 -- pbuc1_derefidx_vbuxx=vbuaa
sta SCREEN,x
//SEG19 [7] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG20 [8] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuaa=_inc_vbuaa
clc
adc #1
//SEG21 [9] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $a) goto main::@1 -- vbuxx_lt_vbuc1_then_la1
cpx #$a
bcc b1
//SEG22 main::@return
//SEG23 [10] return
rts
}

View File

@ -0,0 +1,17 @@
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@1
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(byte) main::i
(byte) main::i#1 reg byte x 11.0
(byte) main::i#2 reg byte x 16.5
(byte) main::j
(byte) main::j#1 reg byte a 11.0
(byte) main::j#2 reg byte a 11.0
reg byte a [ main::j#2 main::j#1 ]
reg byte x [ main::i#2 main::i#1 ]