mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-03 12:07:26 +00:00
Implemented support for comma-separated variable declarations.
This commit is contained in:
parent
0f5d8f906b
commit
24ca7e9c68
@ -28,7 +28,16 @@ decl
|
||||
;
|
||||
|
||||
declVariable
|
||||
: directive* typeDecl directive* NAME ('=' expr)? ';'
|
||||
: directive* typeDecl directive* declVariableList ';'
|
||||
;
|
||||
|
||||
declVariableList
|
||||
: declVariableInit
|
||||
| declVariableList ',' declVariableInit
|
||||
;
|
||||
|
||||
declVariableInit
|
||||
: NAME ('=' expr)?
|
||||
;
|
||||
|
||||
declFunction
|
||||
@ -60,12 +69,12 @@ stmtSeq
|
||||
stmt
|
||||
: declVariable #stmtDeclVar
|
||||
| '{' stmtSeq? '}' #stmtBlock
|
||||
| expr ';' #stmtExpr
|
||||
| 'if' '(' expr ')' stmt ( 'else' stmt )? #stmtIfElse
|
||||
| directive* 'while' '(' expr ')' stmt #stmtWhile
|
||||
| directive* 'do' stmt 'while' '(' expr ')' ';' #stmtDoWhile
|
||||
| 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
|
||||
| 'return' expr? ';' #stmtReturn
|
||||
| 'return' commaExpr? ';' #stmtReturn
|
||||
| 'break' ';' #stmtBreak
|
||||
| 'continue' ';' #stmtContinue
|
||||
| 'asm' asmDirectives? '{' asmLines '}' #stmtAsm
|
||||
|
@ -92,13 +92,13 @@ WS=91
|
||||
COMMENT_LINE=92
|
||||
COMMENT_BLOCK=93
|
||||
'import'=1
|
||||
'='=2
|
||||
';'=3
|
||||
'('=4
|
||||
')'=5
|
||||
'{'=6
|
||||
'}'=7
|
||||
','=8
|
||||
';'=2
|
||||
','=3
|
||||
'='=4
|
||||
'('=5
|
||||
')'=6
|
||||
'{'=7
|
||||
'}'=8
|
||||
'const'=9
|
||||
'extern'=10
|
||||
'align'=11
|
||||
|
@ -95,6 +95,30 @@ public class KickCBaseListener implements KickCListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDeclVariable(KickCParser.DeclVariableContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterDeclVariableList(KickCParser.DeclVariableListContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDeclVariableList(KickCParser.DeclVariableListContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterDeclVariableInit(KickCParser.DeclVariableInitContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDeclVariableInit(KickCParser.DeclVariableInitContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -60,6 +60,20 @@ public class KickCBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDeclVariable(KickCParser.DeclVariableContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDeclVariableList(KickCParser.DeclVariableListContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDeclVariableInit(KickCParser.DeclVariableInitContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -56,7 +56,7 @@ public class KickCLexer extends Lexer {
|
||||
};
|
||||
|
||||
private static final String[] _LITERAL_NAMES = {
|
||||
null, "'import'", "'='", "';'", "'('", "')'", "'{'", "'}'", "','", "'const'",
|
||||
null, "'import'", "';'", "','", "'='", "'('", "')'", "'{'", "'}'", "'const'",
|
||||
"'extern'", "'align'", "'register'", "'inline'", "'volatile'", "'interrupt'",
|
||||
"'if'", "'else'", "'while'", "'do'", "'for'", "'return'", "'break'", "'continue'",
|
||||
"'asm'", "':'", "'..'", "'signed'", "'unsigned'", "'*'", "'['", "']'",
|
||||
@ -240,10 +240,10 @@ public class KickCLexer extends Lexer {
|
||||
"\u038f\3\2\2\2\u00c1\u039c\3\2\2\2\u00c3\u03a2\3\2\2\2\u00c5\u03ad\3\2"+
|
||||
"\2\2\u00c7\u00c8\7k\2\2\u00c8\u00c9\7o\2\2\u00c9\u00ca\7r\2\2\u00ca\u00cb"+
|
||||
"\7q\2\2\u00cb\u00cc\7t\2\2\u00cc\u00cd\7v\2\2\u00cd\4\3\2\2\2\u00ce\u00cf"+
|
||||
"\7?\2\2\u00cf\6\3\2\2\2\u00d0\u00d1\7=\2\2\u00d1\b\3\2\2\2\u00d2\u00d3"+
|
||||
"\7*\2\2\u00d3\n\3\2\2\2\u00d4\u00d5\7+\2\2\u00d5\f\3\2\2\2\u00d6\u00d7"+
|
||||
"\7}\2\2\u00d7\16\3\2\2\2\u00d8\u00d9\7\177\2\2\u00d9\20\3\2\2\2\u00da"+
|
||||
"\u00db\7.\2\2\u00db\22\3\2\2\2\u00dc\u00dd\7e\2\2\u00dd\u00de\7q\2\2\u00de"+
|
||||
"\7=\2\2\u00cf\6\3\2\2\2\u00d0\u00d1\7.\2\2\u00d1\b\3\2\2\2\u00d2\u00d3"+
|
||||
"\7?\2\2\u00d3\n\3\2\2\2\u00d4\u00d5\7*\2\2\u00d5\f\3\2\2\2\u00d6\u00d7"+
|
||||
"\7+\2\2\u00d7\16\3\2\2\2\u00d8\u00d9\7}\2\2\u00d9\20\3\2\2\2\u00da\u00db"+
|
||||
"\7\177\2\2\u00db\22\3\2\2\2\u00dc\u00dd\7e\2\2\u00dd\u00de\7q\2\2\u00de"+
|
||||
"\u00df\7p\2\2\u00df\u00e0\7u\2\2\u00e0\u00e1\7v\2\2\u00e1\24\3\2\2\2\u00e2"+
|
||||
"\u00e3\7g\2\2\u00e3\u00e4\7z\2\2\u00e4\u00e5\7v\2\2\u00e5\u00e6\7g\2\2"+
|
||||
"\u00e6\u00e7\7t\2\2\u00e7\u00e8\7p\2\2\u00e8\26\3\2\2\2\u00e9\u00ea\7"+
|
||||
|
@ -92,13 +92,13 @@ WS=91
|
||||
COMMENT_LINE=92
|
||||
COMMENT_BLOCK=93
|
||||
'import'=1
|
||||
'='=2
|
||||
';'=3
|
||||
'('=4
|
||||
')'=5
|
||||
'{'=6
|
||||
'}'=7
|
||||
','=8
|
||||
';'=2
|
||||
','=3
|
||||
'='=4
|
||||
'('=5
|
||||
')'=6
|
||||
'{'=7
|
||||
'}'=8
|
||||
'const'=9
|
||||
'extern'=10
|
||||
'align'=11
|
||||
|
@ -77,6 +77,26 @@ public interface KickCListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDeclVariable(KickCParser.DeclVariableContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link KickCParser#declVariableList}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterDeclVariableList(KickCParser.DeclVariableListContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by {@link KickCParser#declVariableList}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDeclVariableList(KickCParser.DeclVariableListContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link KickCParser#declVariableInit}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterDeclVariableInit(KickCParser.DeclVariableInitContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by {@link KickCParser#declVariableInit}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDeclVariableInit(KickCParser.DeclVariableInitContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link KickCParser#declFunction}.
|
||||
* @param ctx the parse tree
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -52,6 +52,18 @@ public interface KickCVisitor<T> extends ParseTreeVisitor<T> {
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDeclVariable(KickCParser.DeclVariableContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link KickCParser#declVariableList}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDeclVariableList(KickCParser.DeclVariableListContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link KickCParser#declVariableInit}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDeclVariableInit(KickCParser.DeclVariableInitContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link KickCParser#declFunction}.
|
||||
* @param ctx the parse tree
|
||||
|
@ -172,7 +172,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
SymbolType type = (SymbolType) this.visit(ctx.typeDecl());
|
||||
VariableUnversioned param = new VariableUnversioned(ctx.NAME().getText(), getCurrentScope(), type);
|
||||
// Add directives
|
||||
addDirectives(type, param, ctx.directive());
|
||||
List<Directive> directives = getDirectives(ctx.directive());
|
||||
addDirectives(param, type, directives, new StatementSource(ctx));
|
||||
return param;
|
||||
}
|
||||
|
||||
@ -236,7 +237,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
/** will contain the address to generate the KickAssembler-code to. */
|
||||
private RValue address;
|
||||
|
||||
public AsmDirectiveLocation(RValue address) {
|
||||
AsmDirectiveLocation(RValue address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@ -266,7 +267,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
/** bytes for the KickAssembler-code. */
|
||||
private RValue bytes;
|
||||
|
||||
public AsmDirectiveBytes(RValue bytes) {
|
||||
AsmDirectiveBytes(RValue bytes) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
@ -299,7 +300,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
return uses;
|
||||
}
|
||||
|
||||
public AsmDirectiveUses(SymbolVariableRef uses) {
|
||||
AsmDirectiveUses(SymbolVariableRef uses) {
|
||||
this.uses = uses;
|
||||
}
|
||||
|
||||
@ -335,7 +336,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
/** cycles for the KickAssembler-code. */
|
||||
private RValue cycles;
|
||||
|
||||
public AsmDirectiveCycles(RValue cycles) {
|
||||
AsmDirectiveCycles(RValue cycles) {
|
||||
this.cycles = cycles;
|
||||
}
|
||||
|
||||
@ -378,7 +379,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
private class AsmDirectiveClobber implements AsmDirective {
|
||||
private AsmClobber clobber;
|
||||
|
||||
public AsmDirectiveClobber(AsmClobber clobber) {
|
||||
AsmDirectiveClobber(AsmClobber clobber) {
|
||||
this.clobber = clobber;
|
||||
}
|
||||
|
||||
@ -407,9 +408,41 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
return new AsmDirectiveClobber(clobber);
|
||||
}
|
||||
|
||||
/** Holds the declared type when descending into a Variable Declaration. */
|
||||
private SymbolType declVarType = null;
|
||||
/** Holds the declared directives when descending into a Variable Declaration. */
|
||||
private List<Directive> declVarDirectives = null;
|
||||
/** Holds the declared comments when descending into a Variable Declaration. */
|
||||
private List<Comment> declVarComments = null;
|
||||
|
||||
@Override
|
||||
public Object visitDeclVariable(KickCParser.DeclVariableContext ctx) {
|
||||
SymbolType type = (SymbolType) visit(ctx.typeDecl());
|
||||
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.declVarType = null;
|
||||
this.declVarDirectives = null;
|
||||
this.declVarComments = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDeclVariableList(KickCParser.DeclVariableListContext ctx) {
|
||||
if(ctx.declVariableList()!=null) {
|
||||
this.visit(ctx.declVariableList());
|
||||
}
|
||||
this.visit(ctx.declVariableInit());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDeclVariableInit(KickCParser.DeclVariableInitContext ctx) {
|
||||
List<Directive> directives = declVarDirectives;
|
||||
SymbolType type = declVarType;
|
||||
List<Comment> comments = declVarComments;
|
||||
|
||||
String varName = ctx.NAME().getText();
|
||||
VariableUnversioned lValue;
|
||||
try {
|
||||
@ -418,12 +451,11 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
throw new CompileError(e.getMessage(), new StatementSource(ctx));
|
||||
}
|
||||
// Add directives
|
||||
addDirectives(type, lValue, ctx.directive());
|
||||
addDirectives(lValue, type, directives, new StatementSource(ctx));
|
||||
// Array / String variables are implicitly constant
|
||||
if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) {
|
||||
lValue.setDeclaredConstant(true);
|
||||
}
|
||||
List<Comment> comments = getCommentsSymbol(ctx);
|
||||
if(lValue.isDeclaredConstant()) {
|
||||
// Add comments to constant
|
||||
lValue.setComments(ensureUnusedComments(comments));
|
||||
@ -434,7 +466,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
} else {
|
||||
if(type instanceof SymbolTypeInteger) {
|
||||
// Add an zero value initializer
|
||||
ConstantInteger zero = new ConstantInteger(0l);
|
||||
ConstantInteger zero = new ConstantInteger(0L);
|
||||
Statement stmt = new StatementAssignment(lValue.getRef(), zero, new StatementSource(ctx), ensureUnusedComments(comments));
|
||||
sequence.addStatement(stmt);
|
||||
} else if(type instanceof SymbolTypeArray) {
|
||||
@ -449,7 +481,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
} else if(type instanceof SymbolTypePointer) {
|
||||
// Add an zero value initializer
|
||||
SymbolTypePointer typePointer = (SymbolTypePointer) type;
|
||||
ConstantValue zero = new ConstantPointer(0l, typePointer.getElementType());
|
||||
ConstantValue zero = new ConstantPointer(0L, typePointer.getElementType());
|
||||
Statement stmt = new StatementAssignment(lValue.getRef(), zero, new StatementSource(ctx), ensureUnusedComments(comments));
|
||||
sequence.addStatement(stmt);
|
||||
} else {
|
||||
@ -457,23 +489,19 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add declared directives to an lValue (typically a variable).
|
||||
*
|
||||
* @param type The type of the lValue
|
||||
* @param lValue The lValue
|
||||
* @param directivesCtx The directives to add
|
||||
* @param type The type of the lValue
|
||||
* @param directives The directives to add
|
||||
*/
|
||||
private void addDirectives(SymbolType type, SymbolVariable lValue, List<KickCParser.DirectiveContext> directivesCtx) {
|
||||
List<Directive> directives = new ArrayList<>();
|
||||
for(KickCParser.DirectiveContext directiveContext : directivesCtx) {
|
||||
directives.add((Directive) this.visit(directiveContext));
|
||||
}
|
||||
private void addDirectives(SymbolVariable lValue, SymbolType type, List<Directive> directives, StatementSource source) {
|
||||
for(Directive directive : directives) {
|
||||
StatementSource source = new StatementSource(directivesCtx.get(0));
|
||||
if(directive instanceof DirectiveConst) {
|
||||
lValue.setDeclaredConstant(true);
|
||||
} else if(directive instanceof DirectiveVolatile) {
|
||||
@ -497,6 +525,19 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the directives in the parse tree
|
||||
* @param directivesCtx The directives in the parse tree to examine
|
||||
* @return Objects representing the found directives
|
||||
*/
|
||||
private List<Directive> getDirectives(List<KickCParser.DirectiveContext> directivesCtx) {
|
||||
List<Directive> directives = new ArrayList<>();
|
||||
for(KickCParser.DirectiveContext directiveContext : directivesCtx) {
|
||||
directives.add((Directive) this.visit(directiveContext));
|
||||
}
|
||||
return directives;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add declared directives to a procedure.
|
||||
*
|
||||
@ -504,10 +545,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
* @param directivesCtx The directives to add
|
||||
*/
|
||||
private void addDirectives(Procedure procedure, List<KickCParser.DirectiveContext> directivesCtx) {
|
||||
List<Directive> directives = new ArrayList<>();
|
||||
for(KickCParser.DirectiveContext directiveContext : directivesCtx) {
|
||||
directives.add((Directive) this.visit(directiveContext));
|
||||
}
|
||||
List<Directive> directives = getDirectives(directivesCtx);
|
||||
for(Directive directive : directives) {
|
||||
StatementSource source = new StatementSource(directivesCtx.get(0));
|
||||
if(directive instanceof DirectiveInline) {
|
||||
@ -527,10 +565,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
* @param directivesCtx The directives to add
|
||||
*/
|
||||
private void addDirectives(StatementConditionalJump conditional, List<KickCParser.DirectiveContext> directivesCtx) {
|
||||
List<Directive> directives = new ArrayList<>();
|
||||
for(KickCParser.DirectiveContext directiveContext : directivesCtx) {
|
||||
directives.add((Directive) this.visit(directiveContext));
|
||||
}
|
||||
List<Directive> directives = getDirectives(directivesCtx);
|
||||
for(Directive directive : directives) {
|
||||
StatementSource source = new StatementSource(directivesCtx.get(0));
|
||||
if(directive instanceof DirectiveInline) {
|
||||
@ -603,9 +638,9 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
|
||||
@Override
|
||||
public Void visitStmtExpr(KickCParser.StmtExprContext ctx) {
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.expr());
|
||||
this.visit(ctx.expr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.expr());
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.commaExpr());
|
||||
this.visit(ctx.commaExpr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.commaExpr());
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -613,15 +648,15 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
public Void visitStmtIfElse(KickCParser.StmtIfElseContext ctx) {
|
||||
KickCParser.StmtContext ifStmt = ctx.stmt(0);
|
||||
KickCParser.StmtContext elseStmt = ctx.stmt(1);
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.expr());
|
||||
RValue rValue = (RValue) this.visit(ctx.expr());
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.commaExpr());
|
||||
RValue rValue = (RValue) this.visit(ctx.commaExpr());
|
||||
List<Comment> comments = ensureUnusedComments(getCommentsSymbol(ctx));
|
||||
|
||||
if(elseStmt == null) {
|
||||
// If without else - skip the entire section if condition not met
|
||||
VariableRef notExprVar = getCurrentScope().addVariableIntermediate().getRef();
|
||||
sequence.addStatement(new StatementAssignment(notExprVar, null, Operators.LOGIC_NOT, rValue, new StatementSource(ctx), comments));
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.expr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.commaExpr());
|
||||
Label endJumpLabel = getCurrentScope().addLabelIntermediate();
|
||||
sequence.addStatement(new StatementConditionalJump(notExprVar, endJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
|
||||
this.visit(ifStmt);
|
||||
@ -629,7 +664,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
sequence.addStatement(new StatementLabel(endJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
|
||||
} else {
|
||||
// If with else - jump to if section if condition met - fall into else otherwise.
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.expr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.commaExpr());
|
||||
Label ifJumpLabel = getCurrentScope().addLabelIntermediate();
|
||||
sequence.addStatement(new StatementConditionalJump(rValue, ifJumpLabel.getRef(), new StatementSource(ctx), comments));
|
||||
// Add else body
|
||||
@ -661,26 +696,26 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
this.loopScope = loopScope;
|
||||
}
|
||||
|
||||
public Label getBreakLabel() {
|
||||
Label getBreakLabel() {
|
||||
return breakLabel;
|
||||
}
|
||||
|
||||
public Label getOrCreateBreakLabel() {
|
||||
Label getOrCreateBreakLabel() {
|
||||
if(breakLabel == null) {
|
||||
breakLabel = loopScope.addLabelIntermediate();
|
||||
}
|
||||
return breakLabel;
|
||||
}
|
||||
|
||||
public Label getContinueLabel() {
|
||||
Label getContinueLabel() {
|
||||
return continueLabel;
|
||||
}
|
||||
|
||||
public void setContinueLabel(Label continueLabel) {
|
||||
void setContinueLabel(Label continueLabel) {
|
||||
this.continueLabel = continueLabel;
|
||||
}
|
||||
|
||||
public Label getOrCreateContinueLabel() {
|
||||
Label getOrCreateContinueLabel() {
|
||||
if(continueLabel == null) {
|
||||
continueLabel = loopScope.addLabelIntermediate();
|
||||
}
|
||||
@ -704,9 +739,9 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
List<Comment> comments = ensureUnusedComments(getCommentsSymbol(ctx));
|
||||
StatementLabel beginJumpTarget = new StatementLabel(beginJumpLabel.getRef(), new StatementSource(ctx), comments);
|
||||
sequence.addStatement(beginJumpTarget);
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.expr());
|
||||
RValue rValue = (RValue) this.visit(ctx.expr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.expr());
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.commaExpr());
|
||||
RValue rValue = (RValue) this.visit(ctx.commaExpr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.commaExpr());
|
||||
StatementConditionalJump doJmpStmt = new StatementConditionalJump(rValue, doJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS);
|
||||
sequence.addStatement(doJmpStmt);
|
||||
Statement endJmpStmt = new StatementJump(endJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS);
|
||||
@ -739,9 +774,9 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
sequence.addStatement(beginJumpTarget);
|
||||
addLoopBody(ctx.stmt());
|
||||
addLoopContinueLabel(loopStack.peek(), ctx);
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.expr());
|
||||
RValue rValue = (RValue) this.visit(ctx.expr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.expr());
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.commaExpr());
|
||||
RValue rValue = (RValue) this.visit(ctx.commaExpr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.commaExpr());
|
||||
StatementConditionalJump doJmpStmt = new StatementConditionalJump(rValue, beginJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS);
|
||||
sequence.addStatement(doJmpStmt);
|
||||
addDirectives(doJmpStmt, ctx.directive());
|
||||
@ -893,7 +928,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
throw new CompileError(e.getMessage(), new StatementSource(forDeclCtx));
|
||||
}
|
||||
// Add directives
|
||||
addDirectives(type, lValue, forDeclCtx.directive());
|
||||
List<Directive> directives = getDirectives(forDeclCtx.directive());
|
||||
addDirectives(lValue, type, directives, new StatementSource(forDeclCtx));
|
||||
} else {
|
||||
lValue = getCurrentScope().getVariable(varName);
|
||||
}
|
||||
@ -1018,7 +1054,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
@Override
|
||||
public Void visitStmtReturn(KickCParser.StmtReturnContext ctx) {
|
||||
Procedure procedure = getCurrentProcedure();
|
||||
KickCParser.ExprContext exprCtx = ctx.expr();
|
||||
KickCParser.CommaExprContext exprCtx = ctx.commaExpr();
|
||||
RValue rValue;
|
||||
if(exprCtx != null) {
|
||||
PrePostModifierHandler.addPreModifiers(this, exprCtx);
|
||||
@ -1285,14 +1321,12 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
|
||||
@Override
|
||||
public Object visitExprPreMod(KickCParser.ExprPreModContext ctx) {
|
||||
RValue child = (RValue) this.visit(ctx.expr());
|
||||
return child;
|
||||
return this.visit(ctx.expr());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitExprPostMod(KickCParser.ExprPostModContext ctx) {
|
||||
RValue child = (RValue) this.visit(ctx.expr());
|
||||
return child;
|
||||
return this.visit(ctx.expr());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -37,15 +37,26 @@ public class TestPrograms {
|
||||
// compileAndCompare("pointer-cast-3");
|
||||
//}
|
||||
|
||||
@Test
|
||||
public void testCommaDecl() throws IOException, URISyntaxException {
|
||||
compileAndCompare("comma-decl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommaExprFor() throws IOException, URISyntaxException {
|
||||
compileAndCompare("comma-expr-for");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommaExpr2() throws IOException, URISyntaxException {
|
||||
compileAndCompare("comma-expr-2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommaExpr1() throws IOException, URISyntaxException {
|
||||
compileAndCompare("comma-expr-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForRangedNoVar() throws IOException, URISyntaxException {
|
||||
assertError("for-ranged-novar", "Ranged for() must have iteration variable");
|
||||
|
9
src/test/kc/comma-decl.kc
Normal file
9
src/test/kc/comma-decl.kc
Normal file
@ -0,0 +1,9 @@
|
||||
// Tests comma-separated declarations
|
||||
|
||||
void main() {
|
||||
const byte* SCREEN = $400;
|
||||
byte b = 'c', c = b+1, d = c+1;
|
||||
SCREEN[0] = b;
|
||||
SCREEN[1] = c;
|
||||
SCREEN[2] = d;
|
||||
}
|
10
src/test/kc/comma-expr-2.kc
Normal file
10
src/test/kc/comma-expr-2.kc
Normal file
@ -0,0 +1,10 @@
|
||||
// Tests simple comma-expressions (without parenthesis)
|
||||
|
||||
void main() {
|
||||
const byte* SCREEN = $400;
|
||||
byte b;
|
||||
byte c;
|
||||
b = 1,2,3;
|
||||
c = 1+3,b+1;
|
||||
SCREEN[1,0] = c;
|
||||
}
|
17
src/test/ref/comma-decl.asm
Normal file
17
src/test/ref/comma-decl.asm
Normal file
@ -0,0 +1,17 @@
|
||||
// Tests comma-separated declarations
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.const b = 'c'
|
||||
.const c = b+1
|
||||
.const d = c+1
|
||||
lda #b
|
||||
sta SCREEN
|
||||
lda #c
|
||||
sta SCREEN+1
|
||||
lda #d
|
||||
sta SCREEN+2
|
||||
rts
|
||||
}
|
17
src/test/ref/comma-decl.cfg
Normal file
17
src/test/ref/comma-decl.cfg
Normal file
@ -0,0 +1,17 @@
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0
|
||||
[5] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::c#0
|
||||
[6] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::d#0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[7] return
|
||||
to:@return
|
274
src/test/ref/comma-decl.log
Normal file
274
src/test/ref/comma-decl.log
Normal file
@ -0,0 +1,274 @@
|
||||
Identified constant variable (byte) main::b
|
||||
|
||||
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::b#0 ← (byte) 'c'
|
||||
(byte/signed word/word/dword/signed dword~) main::$0 ← (byte) main::b#0 + (byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
(byte) main::c#0 ← (byte/signed word/word/dword/signed dword~) main::$0
|
||||
(byte/signed word/word/dword/signed dword~) main::$1 ← (byte) main::c#0 + (byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
(byte) main::d#0 ← (byte/signed word/word/dword/signed dword~) main::$1
|
||||
*((byte*) main::SCREEN#0 + (byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte) main::b#0
|
||||
*((byte*) main::SCREEN#0 + (byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte) main::c#0
|
||||
*((byte*) main::SCREEN#0 + (byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte) main::d#0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
call main
|
||||
to:@2
|
||||
@2: scope:[] from @1
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(label) @1
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(byte/signed word/word/dword/signed dword~) main::$0
|
||||
(byte/signed word/word/dword/signed dword~) main::$1
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(byte*) main::SCREEN#0
|
||||
(byte) main::b
|
||||
(byte) main::b#0
|
||||
(byte) main::c
|
||||
(byte) main::c#0
|
||||
(byte) main::d
|
||||
(byte) main::d#0
|
||||
|
||||
Culled Empty Block (label) @2
|
||||
Successful SSA optimization Pass2CullEmptyBlocks
|
||||
Alias (byte) main::c#0 = (byte/signed word/word/dword/signed dword~) main::$0
|
||||
Alias (byte) main::d#0 = (byte/signed word/word/dword/signed dword~) main::$1
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Constant (const byte*) main::SCREEN#0 = ((byte*))$400
|
||||
Constant (const byte) main::b#0 = 'c'
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant (const byte) main::c#0 = main::b#0+1
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant (const byte) main::d#0 = main::c#0+1
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Consolidated array index constant in *(main::SCREEN#0+0)
|
||||
Consolidated array index constant in *(main::SCREEN#0+1)
|
||||
Consolidated array index constant in *(main::SCREEN#0+2)
|
||||
Successful SSA optimization Pass2ConstantAdditionElimination
|
||||
Simplifying constant plus zero main::SCREEN#0+0
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
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
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @end
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0
|
||||
[5] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::c#0
|
||||
[6] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::d#0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[7] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(void()) main()
|
||||
(byte*) main::SCREEN
|
||||
(byte) main::b
|
||||
(byte) main::c
|
||||
(byte) main::d
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
|
||||
INITIAL ASM
|
||||
//SEG0 File Comments
|
||||
// Tests comma-separated declarations
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//SEG3 @begin
|
||||
bbegin:
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG5 @1
|
||||
b1:
|
||||
//SEG6 [2] call main
|
||||
jsr main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG8 @end
|
||||
bend:
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.const b = 'c'
|
||||
.const c = b+1
|
||||
.const d = c+1
|
||||
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0 -- _deref_pbuc1=vbuc2
|
||||
lda #b
|
||||
sta SCREEN
|
||||
//SEG11 [5] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::c#0 -- _deref_pbuc1=vbuc2
|
||||
lda #c
|
||||
sta SCREEN+1
|
||||
//SEG12 [6] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::d#0 -- _deref_pbuc1=vbuc2
|
||||
lda #d
|
||||
sta SCREEN+2
|
||||
jmp breturn
|
||||
//SEG13 main::@return
|
||||
breturn:
|
||||
//SEG14 [7] return
|
||||
rts
|
||||
}
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [5] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::c#0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [6] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::d#0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 39 combination
|
||||
Uplifting [] best 39 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
// Tests comma-separated declarations
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//SEG3 @begin
|
||||
bbegin:
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG5 @1
|
||||
b1:
|
||||
//SEG6 [2] call main
|
||||
jsr main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG8 @end
|
||||
bend:
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.const b = 'c'
|
||||
.const c = b+1
|
||||
.const d = c+1
|
||||
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0 -- _deref_pbuc1=vbuc2
|
||||
lda #b
|
||||
sta SCREEN
|
||||
//SEG11 [5] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::c#0 -- _deref_pbuc1=vbuc2
|
||||
lda #c
|
||||
sta SCREEN+1
|
||||
//SEG12 [6] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::d#0 -- _deref_pbuc1=vbuc2
|
||||
lda #d
|
||||
sta SCREEN+2
|
||||
jmp breturn
|
||||
//SEG13 main::@return
|
||||
breturn:
|
||||
//SEG14 [7] return
|
||||
rts
|
||||
}
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction b1_from_bbegin:
|
||||
Removing instruction b1:
|
||||
Removing instruction bend_from_b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction bend:
|
||||
Removing instruction breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Updating BasicUpstart to call main directly
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction bbegin:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
(byte) main::b
|
||||
(const byte) main::b#0 b = (byte) 'c'
|
||||
(byte) main::c
|
||||
(const byte) main::c#0 c = (const byte) main::b#0+(byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
(byte) main::d
|
||||
(const byte) main::d#0 d = (const byte) main::c#0+(byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 24
|
||||
|
||||
//SEG0 File Comments
|
||||
// Tests comma-separated declarations
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//SEG3 @begin
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
//SEG5 @1
|
||||
//SEG6 [2] call main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
//SEG8 @end
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.const b = 'c'
|
||||
.const c = b+1
|
||||
.const d = c+1
|
||||
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) main::b#0 -- _deref_pbuc1=vbuc2
|
||||
lda #b
|
||||
sta SCREEN
|
||||
//SEG11 [5] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::c#0 -- _deref_pbuc1=vbuc2
|
||||
lda #c
|
||||
sta SCREEN+1
|
||||
//SEG12 [6] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::d#0 -- _deref_pbuc1=vbuc2
|
||||
lda #d
|
||||
sta SCREEN+2
|
||||
//SEG13 main::@return
|
||||
//SEG14 [7] return
|
||||
rts
|
||||
}
|
||||
|
14
src/test/ref/comma-decl.sym
Normal file
14
src/test/ref/comma-decl.sym
Normal file
@ -0,0 +1,14 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
(byte) main::b
|
||||
(const byte) main::b#0 b = (byte) 'c'
|
||||
(byte) main::c
|
||||
(const byte) main::c#0 c = (const byte) main::b#0+(byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
(byte) main::d
|
||||
(const byte) main::d#0 d = (const byte) main::c#0+(byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
|
11
src/test/ref/comma-expr-2.asm
Normal file
11
src/test/ref/comma-expr-2.asm
Normal file
@ -0,0 +1,11 @@
|
||||
// Tests simple comma-expressions (without parenthesis)
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.const c = 1+3
|
||||
lda #c
|
||||
sta SCREEN
|
||||
rts
|
||||
}
|
15
src/test/ref/comma-expr-2.cfg
Normal file
15
src/test/ref/comma-expr-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) main::c#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[5] return
|
||||
to:@return
|
226
src/test/ref/comma-expr-2.log
Normal file
226
src/test/ref/comma-expr-2.log
Normal file
@ -0,0 +1,226 @@
|
||||
|
||||
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::c#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
|
||||
(byte/signed byte/word/signed word/dword/signed dword~) main::$0 ← (byte/signed byte/word/signed word/dword/signed dword) 1 + (byte/signed byte/word/signed word/dword/signed dword) 3
|
||||
(byte) main::c#1 ← (byte/signed byte/word/signed word/dword/signed dword~) main::$0
|
||||
*((byte*) main::SCREEN#0 + (byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte) main::c#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
call main
|
||||
to:@2
|
||||
@2: scope:[] from @1
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(label) @1
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(byte/signed byte/word/signed word/dword/signed dword~) main::$0
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(byte*) main::SCREEN#0
|
||||
(byte) main::c
|
||||
(byte) main::c#0
|
||||
(byte) main::c#1
|
||||
|
||||
Culled Empty Block (label) @2
|
||||
Successful SSA optimization Pass2CullEmptyBlocks
|
||||
Alias (byte) main::c#1 = (byte/signed byte/word/signed word/dword/signed dword~) main::$0
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Constant (const byte*) main::SCREEN#0 = ((byte*))$400
|
||||
Constant (const byte) main::c#0 = 0
|
||||
Constant (const byte) main::c#1 = 1+3
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Consolidated array index constant in *(main::SCREEN#0+0)
|
||||
Successful SSA optimization Pass2ConstantAdditionElimination
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
Simplifying constant plus zero main::SCREEN#0+0
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
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
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @end
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] *((const byte*) main::SCREEN#0) ← (const byte) main::c#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[5] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(void()) main()
|
||||
(byte*) main::SCREEN
|
||||
(byte) main::c
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
|
||||
INITIAL ASM
|
||||
//SEG0 File Comments
|
||||
// Tests simple comma-expressions (without parenthesis)
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//SEG3 @begin
|
||||
bbegin:
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG5 @1
|
||||
b1:
|
||||
//SEG6 [2] call main
|
||||
jsr main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG8 @end
|
||||
bend:
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.const c = 1+3
|
||||
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) main::c#1 -- _deref_pbuc1=vbuc2
|
||||
lda #c
|
||||
sta SCREEN
|
||||
jmp breturn
|
||||
//SEG11 main::@return
|
||||
breturn:
|
||||
//SEG12 [5] return
|
||||
rts
|
||||
}
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [4] *((const byte*) main::SCREEN#0) ← (const byte) main::c#1 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 27 combination
|
||||
Uplifting [] best 27 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
// Tests simple comma-expressions (without parenthesis)
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//SEG3 @begin
|
||||
bbegin:
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG5 @1
|
||||
b1:
|
||||
//SEG6 [2] call main
|
||||
jsr main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG8 @end
|
||||
bend:
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.const c = 1+3
|
||||
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) main::c#1 -- _deref_pbuc1=vbuc2
|
||||
lda #c
|
||||
sta SCREEN
|
||||
jmp breturn
|
||||
//SEG11 main::@return
|
||||
breturn:
|
||||
//SEG12 [5] return
|
||||
rts
|
||||
}
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction b1_from_bbegin:
|
||||
Removing instruction b1:
|
||||
Removing instruction bend_from_b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction bend:
|
||||
Removing instruction breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Updating BasicUpstart to call main directly
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction bbegin:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
(byte) main::c
|
||||
(const byte) main::c#1 c = (byte/signed byte/word/signed word/dword/signed dword) 1+(byte/signed byte/word/signed word/dword/signed dword) 3
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 12
|
||||
|
||||
//SEG0 File Comments
|
||||
// Tests simple comma-expressions (without parenthesis)
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//SEG3 @begin
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
//SEG5 @1
|
||||
//SEG6 [2] call main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
//SEG8 @end
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.const c = 1+3
|
||||
//SEG10 [4] *((const byte*) main::SCREEN#0) ← (const byte) main::c#1 -- _deref_pbuc1=vbuc2
|
||||
lda #c
|
||||
sta SCREEN
|
||||
//SEG11 main::@return
|
||||
//SEG12 [5] return
|
||||
rts
|
||||
}
|
||||
|
10
src/test/ref/comma-expr-2.sym
Normal file
10
src/test/ref/comma-expr-2.sym
Normal file
@ -0,0 +1,10 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
(byte) main::c
|
||||
(const byte) main::c#1 c = (byte/signed byte/word/signed word/dword/signed dword) 1+(byte/signed byte/word/signed word/dword/signed dword) 3
|
||||
|
Loading…
Reference in New Issue
Block a user