mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-11 04:29:53 +00:00
Added support for labels and goto. Closes #687
This commit is contained in:
parent
5ee8749d06
commit
1deb381c57
@ -202,6 +202,7 @@ public class Compiler {
|
||||
getLog().append(procedureCompilation.getStatementSequence().toString(program));
|
||||
}
|
||||
}
|
||||
new Pass1AssertJumpLabels(program).execute();
|
||||
new Pass1GenerateControlFlowGraph(program).execute();
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("FIRST CONTROL FLOW GRAPH");
|
||||
|
@ -88,6 +88,7 @@ SWITCH: 'switch' ;
|
||||
RETURN: 'return' ;
|
||||
BREAK: 'break' ;
|
||||
CONTINUE: 'continue' ;
|
||||
GOTO: 'goto' ;
|
||||
ASM: 'asm' { asmEnter=true; };
|
||||
DEFAULT : 'default' ;
|
||||
CASE : 'case' ;
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -63,95 +63,96 @@ SWITCH=62
|
||||
RETURN=63
|
||||
BREAK=64
|
||||
CONTINUE=65
|
||||
ASM=66
|
||||
DEFAULT=67
|
||||
CASE=68
|
||||
STRUCT=69
|
||||
UNION=70
|
||||
ENUM=71
|
||||
SIZEOF=72
|
||||
TYPEID=73
|
||||
DEFINED=74
|
||||
KICKASM=75
|
||||
RESOURCE=76
|
||||
USES=77
|
||||
CLOBBERS=78
|
||||
BYTES=79
|
||||
CYCLES=80
|
||||
LOGIC_NOT=81
|
||||
SIMPLETYPE=82
|
||||
BOOLEAN=83
|
||||
KICKASM_BODY=84
|
||||
IMPORT=85
|
||||
INCLUDE=86
|
||||
PRAGMA=87
|
||||
DEFINE=88
|
||||
DEFINE_CONTINUE=89
|
||||
UNDEF=90
|
||||
IFDEF=91
|
||||
IFNDEF=92
|
||||
IFIF=93
|
||||
ELIF=94
|
||||
IFELSE=95
|
||||
ENDIF=96
|
||||
ERROR=97
|
||||
NUMBER=98
|
||||
NUMFLOAT=99
|
||||
BINFLOAT=100
|
||||
DECFLOAT=101
|
||||
HEXFLOAT=102
|
||||
NUMINT=103
|
||||
BININTEGER=104
|
||||
DECINTEGER=105
|
||||
HEXINTEGER=106
|
||||
NAME=107
|
||||
STRING=108
|
||||
CHAR=109
|
||||
WS=110
|
||||
COMMENT_LINE=111
|
||||
COMMENT_BLOCK=112
|
||||
ASM_BYTE=113
|
||||
ASM_MNEMONIC=114
|
||||
ASM_IMM=115
|
||||
ASM_COLON=116
|
||||
ASM_COMMA=117
|
||||
ASM_PAR_BEGIN=118
|
||||
ASM_PAR_END=119
|
||||
ASM_BRACKET_BEGIN=120
|
||||
ASM_BRACKET_END=121
|
||||
ASM_DOT=122
|
||||
ASM_SHIFT_LEFT=123
|
||||
ASM_SHIFT_RIGHT=124
|
||||
ASM_PLUS=125
|
||||
ASM_MINUS=126
|
||||
ASM_LESS_THAN=127
|
||||
ASM_GREATER_THAN=128
|
||||
ASM_MULTIPLY=129
|
||||
ASM_DIVIDE=130
|
||||
ASM_CURLY_BEGIN=131
|
||||
ASM_CURLY_END=132
|
||||
ASM_NUMBER=133
|
||||
ASM_NUMFLOAT=134
|
||||
ASM_BINFLOAT=135
|
||||
ASM_DECFLOAT=136
|
||||
ASM_HEXFLOAT=137
|
||||
ASM_NUMINT=138
|
||||
ASM_BININTEGER=139
|
||||
ASM_DECINTEGER=140
|
||||
ASM_HEXINTEGER=141
|
||||
ASM_CHAR=142
|
||||
ASM_MULTI_REL=143
|
||||
ASM_MULTI_NAME=144
|
||||
ASM_NAME=145
|
||||
ASM_TAG=146
|
||||
ASM_WS=147
|
||||
ASM_COMMENT_LINE=148
|
||||
ASM_COMMENT_BLOCK=149
|
||||
IMPORT_SYSTEMFILE=150
|
||||
IMPORT_LOCALFILE=151
|
||||
IMPORT_WS=152
|
||||
IMPORT_COMMENT_LINE=153
|
||||
IMPORT_COMMENT_BLOCK=154
|
||||
GOTO=66
|
||||
ASM=67
|
||||
DEFAULT=68
|
||||
CASE=69
|
||||
STRUCT=70
|
||||
UNION=71
|
||||
ENUM=72
|
||||
SIZEOF=73
|
||||
TYPEID=74
|
||||
DEFINED=75
|
||||
KICKASM=76
|
||||
RESOURCE=77
|
||||
USES=78
|
||||
CLOBBERS=79
|
||||
BYTES=80
|
||||
CYCLES=81
|
||||
LOGIC_NOT=82
|
||||
SIMPLETYPE=83
|
||||
BOOLEAN=84
|
||||
KICKASM_BODY=85
|
||||
IMPORT=86
|
||||
INCLUDE=87
|
||||
PRAGMA=88
|
||||
DEFINE=89
|
||||
DEFINE_CONTINUE=90
|
||||
UNDEF=91
|
||||
IFDEF=92
|
||||
IFNDEF=93
|
||||
IFIF=94
|
||||
ELIF=95
|
||||
IFELSE=96
|
||||
ENDIF=97
|
||||
ERROR=98
|
||||
NUMBER=99
|
||||
NUMFLOAT=100
|
||||
BINFLOAT=101
|
||||
DECFLOAT=102
|
||||
HEXFLOAT=103
|
||||
NUMINT=104
|
||||
BININTEGER=105
|
||||
DECINTEGER=106
|
||||
HEXINTEGER=107
|
||||
NAME=108
|
||||
STRING=109
|
||||
CHAR=110
|
||||
WS=111
|
||||
COMMENT_LINE=112
|
||||
COMMENT_BLOCK=113
|
||||
ASM_BYTE=114
|
||||
ASM_MNEMONIC=115
|
||||
ASM_IMM=116
|
||||
ASM_COLON=117
|
||||
ASM_COMMA=118
|
||||
ASM_PAR_BEGIN=119
|
||||
ASM_PAR_END=120
|
||||
ASM_BRACKET_BEGIN=121
|
||||
ASM_BRACKET_END=122
|
||||
ASM_DOT=123
|
||||
ASM_SHIFT_LEFT=124
|
||||
ASM_SHIFT_RIGHT=125
|
||||
ASM_PLUS=126
|
||||
ASM_MINUS=127
|
||||
ASM_LESS_THAN=128
|
||||
ASM_GREATER_THAN=129
|
||||
ASM_MULTIPLY=130
|
||||
ASM_DIVIDE=131
|
||||
ASM_CURLY_BEGIN=132
|
||||
ASM_CURLY_END=133
|
||||
ASM_NUMBER=134
|
||||
ASM_NUMFLOAT=135
|
||||
ASM_BINFLOAT=136
|
||||
ASM_DECFLOAT=137
|
||||
ASM_HEXFLOAT=138
|
||||
ASM_NUMINT=139
|
||||
ASM_BININTEGER=140
|
||||
ASM_DECINTEGER=141
|
||||
ASM_HEXINTEGER=142
|
||||
ASM_CHAR=143
|
||||
ASM_MULTI_REL=144
|
||||
ASM_MULTI_NAME=145
|
||||
ASM_NAME=146
|
||||
ASM_TAG=147
|
||||
ASM_WS=148
|
||||
ASM_COMMENT_LINE=149
|
||||
ASM_COMMENT_BLOCK=150
|
||||
IMPORT_SYSTEMFILE=151
|
||||
IMPORT_LOCALFILE=152
|
||||
IMPORT_WS=153
|
||||
IMPORT_COMMENT_LINE=154
|
||||
IMPORT_COMMENT_BLOCK=155
|
||||
';'=8
|
||||
'..'=11
|
||||
'...'=12
|
||||
@ -197,33 +198,34 @@ IMPORT_COMMENT_BLOCK=154
|
||||
'return'=63
|
||||
'break'=64
|
||||
'continue'=65
|
||||
'asm'=66
|
||||
'default'=67
|
||||
'case'=68
|
||||
'struct'=69
|
||||
'union'=70
|
||||
'enum'=71
|
||||
'sizeof'=72
|
||||
'typeid'=73
|
||||
'defined'=74
|
||||
'kickasm'=75
|
||||
'resource'=76
|
||||
'uses'=77
|
||||
'clobbers'=78
|
||||
'bytes'=79
|
||||
'cycles'=80
|
||||
'!'=81
|
||||
'#import'=85
|
||||
'#include'=86
|
||||
'#pragma'=87
|
||||
'#define'=88
|
||||
'#undef'=90
|
||||
'#ifdef'=91
|
||||
'#ifndef'=92
|
||||
'#if'=93
|
||||
'#elif'=94
|
||||
'#else'=95
|
||||
'#endif'=96
|
||||
'#error'=97
|
||||
'.byte'=113
|
||||
'#'=115
|
||||
'goto'=66
|
||||
'asm'=67
|
||||
'default'=68
|
||||
'case'=69
|
||||
'struct'=70
|
||||
'union'=71
|
||||
'enum'=72
|
||||
'sizeof'=73
|
||||
'typeid'=74
|
||||
'defined'=75
|
||||
'kickasm'=76
|
||||
'resource'=77
|
||||
'uses'=78
|
||||
'clobbers'=79
|
||||
'bytes'=80
|
||||
'cycles'=81
|
||||
'!'=82
|
||||
'#import'=86
|
||||
'#include'=87
|
||||
'#pragma'=88
|
||||
'#define'=89
|
||||
'#undef'=91
|
||||
'#ifdef'=92
|
||||
'#ifndef'=93
|
||||
'#if'=94
|
||||
'#elif'=95
|
||||
'#else'=96
|
||||
'#endif'=97
|
||||
'#error'=98
|
||||
'.byte'=114
|
||||
'#'=116
|
||||
|
@ -186,6 +186,8 @@ stmt
|
||||
| ASM asmDirectives? CURLY_BEGIN asmLines ASM_CURLY_END #stmtAsm
|
||||
| kasmContent #stmtDeclKasm
|
||||
| ';' #stmtEmpty
|
||||
| NAME COLON #stmtLabel
|
||||
| GOTO NAME ';' #stmtGoto
|
||||
;
|
||||
|
||||
switchCases:
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -63,95 +63,96 @@ SWITCH=62
|
||||
RETURN=63
|
||||
BREAK=64
|
||||
CONTINUE=65
|
||||
ASM=66
|
||||
DEFAULT=67
|
||||
CASE=68
|
||||
STRUCT=69
|
||||
UNION=70
|
||||
ENUM=71
|
||||
SIZEOF=72
|
||||
TYPEID=73
|
||||
DEFINED=74
|
||||
KICKASM=75
|
||||
RESOURCE=76
|
||||
USES=77
|
||||
CLOBBERS=78
|
||||
BYTES=79
|
||||
CYCLES=80
|
||||
LOGIC_NOT=81
|
||||
SIMPLETYPE=82
|
||||
BOOLEAN=83
|
||||
KICKASM_BODY=84
|
||||
IMPORT=85
|
||||
INCLUDE=86
|
||||
PRAGMA=87
|
||||
DEFINE=88
|
||||
DEFINE_CONTINUE=89
|
||||
UNDEF=90
|
||||
IFDEF=91
|
||||
IFNDEF=92
|
||||
IFIF=93
|
||||
ELIF=94
|
||||
IFELSE=95
|
||||
ENDIF=96
|
||||
ERROR=97
|
||||
NUMBER=98
|
||||
NUMFLOAT=99
|
||||
BINFLOAT=100
|
||||
DECFLOAT=101
|
||||
HEXFLOAT=102
|
||||
NUMINT=103
|
||||
BININTEGER=104
|
||||
DECINTEGER=105
|
||||
HEXINTEGER=106
|
||||
NAME=107
|
||||
STRING=108
|
||||
CHAR=109
|
||||
WS=110
|
||||
COMMENT_LINE=111
|
||||
COMMENT_BLOCK=112
|
||||
ASM_BYTE=113
|
||||
ASM_MNEMONIC=114
|
||||
ASM_IMM=115
|
||||
ASM_COLON=116
|
||||
ASM_COMMA=117
|
||||
ASM_PAR_BEGIN=118
|
||||
ASM_PAR_END=119
|
||||
ASM_BRACKET_BEGIN=120
|
||||
ASM_BRACKET_END=121
|
||||
ASM_DOT=122
|
||||
ASM_SHIFT_LEFT=123
|
||||
ASM_SHIFT_RIGHT=124
|
||||
ASM_PLUS=125
|
||||
ASM_MINUS=126
|
||||
ASM_LESS_THAN=127
|
||||
ASM_GREATER_THAN=128
|
||||
ASM_MULTIPLY=129
|
||||
ASM_DIVIDE=130
|
||||
ASM_CURLY_BEGIN=131
|
||||
ASM_CURLY_END=132
|
||||
ASM_NUMBER=133
|
||||
ASM_NUMFLOAT=134
|
||||
ASM_BINFLOAT=135
|
||||
ASM_DECFLOAT=136
|
||||
ASM_HEXFLOAT=137
|
||||
ASM_NUMINT=138
|
||||
ASM_BININTEGER=139
|
||||
ASM_DECINTEGER=140
|
||||
ASM_HEXINTEGER=141
|
||||
ASM_CHAR=142
|
||||
ASM_MULTI_REL=143
|
||||
ASM_MULTI_NAME=144
|
||||
ASM_NAME=145
|
||||
ASM_TAG=146
|
||||
ASM_WS=147
|
||||
ASM_COMMENT_LINE=148
|
||||
ASM_COMMENT_BLOCK=149
|
||||
IMPORT_SYSTEMFILE=150
|
||||
IMPORT_LOCALFILE=151
|
||||
IMPORT_WS=152
|
||||
IMPORT_COMMENT_LINE=153
|
||||
IMPORT_COMMENT_BLOCK=154
|
||||
GOTO=66
|
||||
ASM=67
|
||||
DEFAULT=68
|
||||
CASE=69
|
||||
STRUCT=70
|
||||
UNION=71
|
||||
ENUM=72
|
||||
SIZEOF=73
|
||||
TYPEID=74
|
||||
DEFINED=75
|
||||
KICKASM=76
|
||||
RESOURCE=77
|
||||
USES=78
|
||||
CLOBBERS=79
|
||||
BYTES=80
|
||||
CYCLES=81
|
||||
LOGIC_NOT=82
|
||||
SIMPLETYPE=83
|
||||
BOOLEAN=84
|
||||
KICKASM_BODY=85
|
||||
IMPORT=86
|
||||
INCLUDE=87
|
||||
PRAGMA=88
|
||||
DEFINE=89
|
||||
DEFINE_CONTINUE=90
|
||||
UNDEF=91
|
||||
IFDEF=92
|
||||
IFNDEF=93
|
||||
IFIF=94
|
||||
ELIF=95
|
||||
IFELSE=96
|
||||
ENDIF=97
|
||||
ERROR=98
|
||||
NUMBER=99
|
||||
NUMFLOAT=100
|
||||
BINFLOAT=101
|
||||
DECFLOAT=102
|
||||
HEXFLOAT=103
|
||||
NUMINT=104
|
||||
BININTEGER=105
|
||||
DECINTEGER=106
|
||||
HEXINTEGER=107
|
||||
NAME=108
|
||||
STRING=109
|
||||
CHAR=110
|
||||
WS=111
|
||||
COMMENT_LINE=112
|
||||
COMMENT_BLOCK=113
|
||||
ASM_BYTE=114
|
||||
ASM_MNEMONIC=115
|
||||
ASM_IMM=116
|
||||
ASM_COLON=117
|
||||
ASM_COMMA=118
|
||||
ASM_PAR_BEGIN=119
|
||||
ASM_PAR_END=120
|
||||
ASM_BRACKET_BEGIN=121
|
||||
ASM_BRACKET_END=122
|
||||
ASM_DOT=123
|
||||
ASM_SHIFT_LEFT=124
|
||||
ASM_SHIFT_RIGHT=125
|
||||
ASM_PLUS=126
|
||||
ASM_MINUS=127
|
||||
ASM_LESS_THAN=128
|
||||
ASM_GREATER_THAN=129
|
||||
ASM_MULTIPLY=130
|
||||
ASM_DIVIDE=131
|
||||
ASM_CURLY_BEGIN=132
|
||||
ASM_CURLY_END=133
|
||||
ASM_NUMBER=134
|
||||
ASM_NUMFLOAT=135
|
||||
ASM_BINFLOAT=136
|
||||
ASM_DECFLOAT=137
|
||||
ASM_HEXFLOAT=138
|
||||
ASM_NUMINT=139
|
||||
ASM_BININTEGER=140
|
||||
ASM_DECINTEGER=141
|
||||
ASM_HEXINTEGER=142
|
||||
ASM_CHAR=143
|
||||
ASM_MULTI_REL=144
|
||||
ASM_MULTI_NAME=145
|
||||
ASM_NAME=146
|
||||
ASM_TAG=147
|
||||
ASM_WS=148
|
||||
ASM_COMMENT_LINE=149
|
||||
ASM_COMMENT_BLOCK=150
|
||||
IMPORT_SYSTEMFILE=151
|
||||
IMPORT_LOCALFILE=152
|
||||
IMPORT_WS=153
|
||||
IMPORT_COMMENT_LINE=154
|
||||
IMPORT_COMMENT_BLOCK=155
|
||||
';'=8
|
||||
'..'=11
|
||||
'...'=12
|
||||
@ -197,33 +198,34 @@ IMPORT_COMMENT_BLOCK=154
|
||||
'return'=63
|
||||
'break'=64
|
||||
'continue'=65
|
||||
'asm'=66
|
||||
'default'=67
|
||||
'case'=68
|
||||
'struct'=69
|
||||
'union'=70
|
||||
'enum'=71
|
||||
'sizeof'=72
|
||||
'typeid'=73
|
||||
'defined'=74
|
||||
'kickasm'=75
|
||||
'resource'=76
|
||||
'uses'=77
|
||||
'clobbers'=78
|
||||
'bytes'=79
|
||||
'cycles'=80
|
||||
'!'=81
|
||||
'#import'=85
|
||||
'#include'=86
|
||||
'#pragma'=87
|
||||
'#define'=88
|
||||
'#undef'=90
|
||||
'#ifdef'=91
|
||||
'#ifndef'=92
|
||||
'#if'=93
|
||||
'#elif'=94
|
||||
'#else'=95
|
||||
'#endif'=96
|
||||
'#error'=97
|
||||
'.byte'=113
|
||||
'#'=115
|
||||
'goto'=66
|
||||
'asm'=67
|
||||
'default'=68
|
||||
'case'=69
|
||||
'struct'=70
|
||||
'union'=71
|
||||
'enum'=72
|
||||
'sizeof'=73
|
||||
'typeid'=74
|
||||
'defined'=75
|
||||
'kickasm'=76
|
||||
'resource'=77
|
||||
'uses'=78
|
||||
'clobbers'=79
|
||||
'bytes'=80
|
||||
'cycles'=81
|
||||
'!'=82
|
||||
'#import'=86
|
||||
'#include'=87
|
||||
'#pragma'=88
|
||||
'#define'=89
|
||||
'#undef'=91
|
||||
'#ifdef'=92
|
||||
'#ifndef'=93
|
||||
'#if'=94
|
||||
'#elif'=95
|
||||
'#else'=96
|
||||
'#endif'=97
|
||||
'#error'=98
|
||||
'.byte'=114
|
||||
'#'=116
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 by ANTLR 4.9
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 by ANTLR 4.9.1
|
||||
package dk.camelot64.kickc.parser;
|
||||
|
||||
|
||||
@ -937,6 +937,30 @@ public class KickCParserBaseListener implements KickCParserListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitStmtEmpty(KickCParser.StmtEmptyContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterStmtLabel(KickCParser.StmtLabelContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitStmtLabel(KickCParser.StmtLabelContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterStmtGoto(KickCParser.StmtGotoContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitStmtGoto(KickCParser.StmtGotoContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 by ANTLR 4.9
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 by ANTLR 4.9.1
|
||||
package dk.camelot64.kickc.parser;
|
||||
|
||||
|
||||
@ -552,6 +552,20 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitStmtEmpty(KickCParser.StmtEmptyContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitStmtLabel(KickCParser.StmtLabelContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitStmtGoto(KickCParser.StmtGotoContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 by ANTLR 4.9
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 by ANTLR 4.9.1
|
||||
package dk.camelot64.kickc.parser;
|
||||
|
||||
|
||||
@ -893,6 +893,30 @@ public interface KickCParserListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitStmtEmpty(KickCParser.StmtEmptyContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code stmtLabel}
|
||||
* labeled alternative in {@link KickCParser#stmt}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterStmtLabel(KickCParser.StmtLabelContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code stmtLabel}
|
||||
* labeled alternative in {@link KickCParser#stmt}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitStmtLabel(KickCParser.StmtLabelContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code stmtGoto}
|
||||
* labeled alternative in {@link KickCParser#stmt}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterStmtGoto(KickCParser.StmtGotoContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code stmtGoto}
|
||||
* labeled alternative in {@link KickCParser#stmt}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitStmtGoto(KickCParser.StmtGotoContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link KickCParser#switchCases}.
|
||||
* @param ctx the parse tree
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 by ANTLR 4.9
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 by ANTLR 4.9.1
|
||||
package dk.camelot64.kickc.parser;
|
||||
|
||||
|
||||
@ -531,6 +531,20 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitStmtEmpty(KickCParser.StmtEmptyContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code stmtLabel}
|
||||
* labeled alternative in {@link KickCParser#stmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitStmtLabel(KickCParser.StmtLabelContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code stmtGoto}
|
||||
* labeled alternative in {@link KickCParser#stmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitStmtGoto(KickCParser.StmtGotoContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link KickCParser#switchCases}.
|
||||
* @param ctx the parse tree
|
||||
|
@ -1,319 +0,0 @@
|
||||
// KickC grammar
|
||||
parser grammar KickCParser;
|
||||
|
||||
options { tokenVocab=KickCLexer; }
|
||||
|
||||
@header {
|
||||
}
|
||||
|
||||
|
||||
@members {
|
||||
// The C parser
|
||||
CParser cParser;
|
||||
// true when a typedef is being created
|
||||
boolean isTypedef;
|
||||
|
||||
public KickCParser(TokenStream input, CParser cParser) {
|
||||
this(input);
|
||||
this.cParser = cParser;
|
||||
this.isTypedef = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
file
|
||||
: declSeq EOF
|
||||
;
|
||||
|
||||
asmFile
|
||||
: asmLines EOF
|
||||
;
|
||||
|
||||
declSeq
|
||||
: decl*
|
||||
;
|
||||
|
||||
decl
|
||||
: declVariables ';'
|
||||
| declFunction
|
||||
| structDef ';'
|
||||
| enumDef ';'
|
||||
| pragma
|
||||
| typeDef ';'
|
||||
;
|
||||
|
||||
declVariables
|
||||
: declType declaratorInitList
|
||||
;
|
||||
|
||||
declaratorInitList
|
||||
: declaratorInit
|
||||
| declaratorInitList COMMA declaratorInit
|
||||
;
|
||||
|
||||
declaratorInit
|
||||
: declarator ('=' expr)? #declVariableInitExpr
|
||||
| declarator '=' kasmContent #declVariableInitKasm
|
||||
;
|
||||
|
||||
typeDef
|
||||
: TYPEDEF declType { isTypedef=true; } declarator
|
||||
;
|
||||
|
||||
declType
|
||||
: directive* type directive*
|
||||
;
|
||||
|
||||
typeSpecifier
|
||||
: type #typeSpecifierSimple
|
||||
| typeSpecifier ASTERISK #typeSpecifierPointer
|
||||
| typeSpecifier BRACKET_BEGIN (expr)? BRACKET_END #typeSpecifierArray
|
||||
;
|
||||
|
||||
declarator
|
||||
: NAME {if(isTypedef) { cParser.addTypedef($NAME.text); isTypedef=false; } } #declaratorName
|
||||
| declarator PAR_BEGIN parameterListDecl? PAR_END #declaratorProcedure
|
||||
| declarator BRACKET_BEGIN (expr)? BRACKET_END #declaratorArray
|
||||
| ASTERISK directive* declarator #declaratorPointer
|
||||
| PAR_BEGIN declarator PAR_END #declaratorPar
|
||||
;
|
||||
|
||||
type
|
||||
: SIMPLETYPE #typeSimple
|
||||
| SIGNEDNESS SIMPLETYPE? #typeSignedSimple
|
||||
| structDef #typeStructDef
|
||||
| structRef #typeStructRef
|
||||
| enumDef #typeEnumDef
|
||||
| enumRef #typeEnumRef
|
||||
| TYPEDEFNAME #typeNamedRef
|
||||
;
|
||||
|
||||
structRef
|
||||
: STRUCT NAME
|
||||
;
|
||||
|
||||
structDef
|
||||
: STRUCT NAME? CURLY_BEGIN structMembers+ CURLY_END
|
||||
;
|
||||
|
||||
structMembers
|
||||
: declVariables ';'
|
||||
;
|
||||
|
||||
enumRef
|
||||
: ENUM NAME
|
||||
;
|
||||
|
||||
enumDef
|
||||
: ENUM NAME? CURLY_BEGIN enumMemberList CURLY_END
|
||||
;
|
||||
|
||||
enumMemberList
|
||||
: enumMember
|
||||
| enumMemberList COMMA enumMember
|
||||
;
|
||||
|
||||
enumMember
|
||||
: NAME ( '=' expr )?
|
||||
;
|
||||
|
||||
declFunction
|
||||
: declType declarator declFunctionBody
|
||||
;
|
||||
|
||||
declFunctionBody
|
||||
: CURLY_BEGIN stmtSeq? CURLY_END
|
||||
;
|
||||
|
||||
parameterListDecl
|
||||
: parameterDecl (COMMA parameterDecl)* ;
|
||||
|
||||
parameterDecl
|
||||
: declType declarator #parameterDeclType
|
||||
| typeSpecifier #parameterDeclTypeSpecifier
|
||||
| PARAM_LIST #parameterDeclList
|
||||
;
|
||||
|
||||
pragma
|
||||
: PRAGMA NAME PAR_BEGIN pragmaParam (COMMA pragmaParam)* PAR_END
|
||||
;
|
||||
|
||||
pragmaParam
|
||||
: NUMBER #pragmaParamNumber
|
||||
| NUMBER RANGE NUMBER #pragmaParamRange
|
||||
| NAME #pragmaParamName
|
||||
| STRING #pragmaParamString
|
||||
| CALLINGCONVENTION #pragmaParamCallingConvention
|
||||
;
|
||||
|
||||
directive
|
||||
: CONST #directiveConst
|
||||
| ALIGN PAR_BEGIN NUMBER PAR_END #directiveAlign
|
||||
| REGISTER ( PAR_BEGIN ( NAME ) PAR_END)? #directiveRegister
|
||||
| ADDRESS_ZEROPAGE #directiveMemoryAreaZp
|
||||
| ADDRESS_MAINMEM #directiveMemoryAreaMain
|
||||
| ADDRESS PAR_BEGIN ( expr ) PAR_END #directiveMemoryAreaAddress
|
||||
| VOLATILE #directiveVolatile
|
||||
| STATIC #directiveStatic
|
||||
| FORM_SSA #directiveFormSsa
|
||||
| FORM_MA #directiveFormMa
|
||||
| EXTERN #directiveExtern
|
||||
| EXPORT #directiveExport
|
||||
| INLINE #directiveInline
|
||||
| INTRINSIC #directiveIntrinsic
|
||||
| INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt
|
||||
| LOCAL_RESERVE PAR_BEGIN pragmaParam ( COMMA pragmaParam )* PAR_END #directiveReserveZp
|
||||
| CALLINGCONVENTION #directiveCallingConvention
|
||||
;
|
||||
|
||||
stmtSeq
|
||||
: stmt+
|
||||
;
|
||||
|
||||
stmt
|
||||
: declVariables ';' #stmtDeclVar
|
||||
| CURLY_BEGIN stmtSeq? CURLY_END #stmtBlock
|
||||
| commaExpr ';' #stmtExpr
|
||||
| IF PAR_BEGIN commaExpr PAR_END stmt ( ELSE stmt )? #stmtIfElse
|
||||
| directive* WHILE PAR_BEGIN commaExpr PAR_END stmt #stmtWhile
|
||||
| directive* DO stmt WHILE PAR_BEGIN commaExpr PAR_END ';' #stmtDoWhile
|
||||
| directive* FOR PAR_BEGIN forLoop PAR_END stmt #stmtFor
|
||||
| SWITCH PAR_BEGIN commaExpr PAR_END CURLY_BEGIN switchCases CURLY_END #stmtSwitch
|
||||
| RETURN commaExpr? ';' #stmtReturn
|
||||
| BREAK ';' #stmtBreak
|
||||
| CONTINUE ';' #stmtContinue
|
||||
| ASM asmDirectives? CURLY_BEGIN asmLines ASM_CURLY_END #stmtAsm
|
||||
| kasmContent #stmtDeclKasm
|
||||
| ';' #stmtEmpty
|
||||
;
|
||||
|
||||
switchCases:
|
||||
switchCase+ ( DEFAULT COLON stmtSeq? )?
|
||||
;
|
||||
|
||||
switchCase:
|
||||
CASE expr COLON stmtSeq?
|
||||
;
|
||||
|
||||
forLoop
|
||||
: forClassicInit ';' forClassicCondition? ';' commaExpr? #forClassic
|
||||
| declType declarator COLON expr RANGE expr #forRange
|
||||
;
|
||||
|
||||
forClassicInit
|
||||
: declVariables? #forClassicInitDecl
|
||||
| commaExpr #forClassicInitExpr
|
||||
;
|
||||
|
||||
forClassicCondition
|
||||
: commaExpr
|
||||
;
|
||||
|
||||
commaExpr
|
||||
: expr #commaNone
|
||||
| commaExpr COMMA expr #commaSimple
|
||||
;
|
||||
|
||||
expr
|
||||
: PAR_BEGIN commaExpr PAR_END #exprPar
|
||||
| expr DOT NAME #exprDot
|
||||
| expr '->' NAME #exprArrow
|
||||
| expr PAR_BEGIN parameterList? PAR_END #exprCall
|
||||
| SIZEOF PAR_BEGIN ( expr | typeSpecifier ) PAR_END #exprSizeOf
|
||||
| TYPEID PAR_BEGIN ( expr | typeSpecifier ) PAR_END #exprTypeId
|
||||
| DEFINED PAR_BEGIN? NAME PAR_END? #exprDefined
|
||||
| expr BRACKET_BEGIN commaExpr BRACKET_END #exprArray
|
||||
| PAR_BEGIN typeSpecifier PAR_END expr #exprCast
|
||||
| ('--' | '++' ) expr #exprPreMod
|
||||
| expr ('--' | '++' ) #exprPostMod
|
||||
| ASTERISK expr #exprPtr
|
||||
| (PLUS | MINUS | LOGIC_NOT | '&'| '~' ) expr #exprUnary
|
||||
| expr (SHIFT_LEFT | SHIFT_RIGHT ) expr #exprBinary
|
||||
| expr (ASTERISK | DIVIDE | '%' ) expr #exprBinary
|
||||
| expr ( PLUS | MINUS ) expr #exprBinary
|
||||
| (LESS_THAN | GREATER_THAN) expr #exprUnary
|
||||
| expr ( '==' | '!=' | LESS_THAN | '<=' | '>=' | GREATER_THAN ) expr #exprBinary
|
||||
| expr ( '&' ) expr #exprBinary
|
||||
| expr ( '^' ) expr #exprBinary
|
||||
| expr ( '|' ) expr #exprBinary
|
||||
| expr ( '&&' ) expr #exprBinary
|
||||
| expr ( '||' ) expr #exprBinary
|
||||
| expr '?' expr COLON expr #exprTernary
|
||||
| <assoc=right> expr '=' expr #exprAssignment
|
||||
| <assoc=right> expr ASSIGN_COMPOUND expr #exprAssignmentCompound
|
||||
| CURLY_BEGIN expr (COMMA expr )* COMMA? CURLY_END #initList
|
||||
| NAME #exprId
|
||||
| NUMBER #exprNumber
|
||||
| STRING+ #exprString
|
||||
| CHAR #exprChar
|
||||
| BOOLEAN #exprBool
|
||||
;
|
||||
|
||||
parameterList
|
||||
: expr (COMMA expr)*
|
||||
;
|
||||
|
||||
kasmContent
|
||||
: KICKASM asmDirectives? KICKASM_BODY
|
||||
;
|
||||
|
||||
asmDirectives
|
||||
: PAR_BEGIN asmDirective ( COMMA asmDirective )* PAR_END
|
||||
;
|
||||
|
||||
asmDirective
|
||||
: RESOURCE STRING #asmDirectiveResource
|
||||
| USES NAME #asmDirectiveUses
|
||||
| CLOBBERS STRING #asmDirectiveClobber
|
||||
| BYTES expr #asmDirectiveBytes
|
||||
| CYCLES expr #asmDirectiveCycles
|
||||
;
|
||||
|
||||
asmLines
|
||||
: asmLine*
|
||||
;
|
||||
|
||||
asmLine
|
||||
: asmLabel
|
||||
| asmInstruction
|
||||
| asmBytes
|
||||
;
|
||||
|
||||
asmLabel
|
||||
: ASM_NAME ASM_COLON ASM_TAG* #asmLabelName
|
||||
| ASM_MULTI_NAME ASM_COLON ASM_TAG* #asmLabelMulti
|
||||
;
|
||||
|
||||
asmInstruction
|
||||
: ASM_MNEMONIC (asmParamMode)? ASM_TAG*
|
||||
;
|
||||
|
||||
asmBytes
|
||||
: ASM_BYTE asmExpr ( ASM_COMMA asmExpr)* ASM_TAG*
|
||||
;
|
||||
|
||||
asmParamMode
|
||||
: asmExpr #asmModeAbs
|
||||
| ASM_IMM asmExpr #asmModeImm
|
||||
| asmExpr ASM_COMMA asmExpr #asmModeAbsXY
|
||||
| ASM_PAR_BEGIN asmExpr ASM_PAR_END ASM_COMMA ASM_NAME #asmModeIndIdxXY
|
||||
| ASM_PAR_BEGIN ASM_PAR_BEGIN asmExpr ASM_PAR_END ASM_PAR_END ASM_COMMA ASM_NAME #asmModeIndLongIdxXY
|
||||
| ASM_PAR_BEGIN asmExpr ASM_COMMA ASM_NAME ASM_PAR_END ASM_COMMA ASM_NAME #asmModeSPIndIdx
|
||||
| ASM_PAR_BEGIN asmExpr ASM_COMMA ASM_NAME ASM_PAR_END #asmModeIdxIndXY
|
||||
| ASM_PAR_BEGIN asmExpr ASM_PAR_END #asmModeInd
|
||||
| ASM_PAR_BEGIN ASM_PAR_BEGIN asmExpr ASM_PAR_END ASM_PAR_END #asmModeIndLong
|
||||
;
|
||||
|
||||
asmExpr
|
||||
: ASM_BRACKET_BEGIN asmExpr ASM_BRACKET_END #asmExprPar
|
||||
| asmExpr ( ASM_DOT ) asmExpr #asmExprBinary
|
||||
| asmExpr ( ASM_SHIFT_LEFT| ASM_SHIFT_RIGHT ) asmExpr #asmExprBinary
|
||||
| (ASM_PLUS | ASM_MINUS| ASM_LESS_THAN | ASM_GREATER_THAN ) asmExpr #asmExprUnary
|
||||
| asmExpr (ASM_MULTIPLY | ASM_DIVIDE ) asmExpr #asmExprBinary
|
||||
| asmExpr ( ASM_PLUS | ASM_MINUS ) asmExpr #asmExprBinary
|
||||
| ASM_NAME #asmExprLabel
|
||||
| ASM_MULTI_REL #asmExprLabelRel
|
||||
| ASM_CURLY_BEGIN ASM_NAME ASM_CURLY_END #asmExprReplace
|
||||
| ASM_NUMBER #asmExprInt
|
||||
| ASM_CHAR #asmExprChar
|
||||
;
|
@ -1739,6 +1739,25 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitStmtLabel(KickCParser.StmtLabelContext ctx) {
|
||||
String labelName = ctx.NAME().getText();
|
||||
if(getCurrentScope().getLocalLabel(labelName)!=null)
|
||||
throw new CompileError("label already defined '"+labelName+"'.", new StatementSource(ctx));
|
||||
Scope procedureScope = getCurrentProcedure();
|
||||
Label label = procedureScope.addLabel(labelName);
|
||||
addStatement(new StatementLabel(label.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitStmtGoto(KickCParser.StmtGotoContext ctx) {
|
||||
String labelName = ctx.NAME().getText();
|
||||
Label label = new Label(labelName, getCurrentScope(), false);
|
||||
addStatement(new StatementJump(label.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitStmtBreak(KickCParser.StmtBreakContext ctx) {
|
||||
if(loopStack.isEmpty()) {
|
||||
|
@ -0,0 +1,41 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ProcedureCompilation;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.StatementSequence;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementJump;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
|
||||
/**
|
||||
* Assert that all jump labels exist
|
||||
*/
|
||||
public class Pass1AssertJumpLabels extends Pass1Base {
|
||||
|
||||
public Pass1AssertJumpLabels(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(Procedure procedure : getProgram().getScope().getAllProcedures(true)) {
|
||||
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
|
||||
StatementSequence statementSequence = procedureCompilation.getStatementSequence();
|
||||
for(Statement statement : statementSequence.getStatements()) {
|
||||
if(statement instanceof StatementJump) {
|
||||
LabelRef jumpLabel = ((StatementJump) statement).getDestination();
|
||||
Label label = getScope().getLabel(jumpLabel);
|
||||
if(label==null) {
|
||||
throw new CompileError("goto label undefined '"+jumpLabel.getLocalName()+"'", statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -9,6 +9,36 @@ import java.io.IOException;
|
||||
*/
|
||||
public class TestProgramsFast extends TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testLabelGoto5() throws IOException {
|
||||
compileAndCompare("labelgoto-5.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLabelGoto4() throws IOException {
|
||||
assertError("labelgoto-4.c", "goto label undefined 'skip'");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLabelGoto3() throws IOException {
|
||||
compileAndCompare("labelgoto-3.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLabelGoto2() throws IOException {
|
||||
compileAndCompare("labelgoto-2.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLabelGoto1() throws IOException {
|
||||
assertError("labelgoto-1.c", "label already defined 'label1'.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLabelGoto0() throws IOException {
|
||||
compileAndCompare("labelgoto-0.c");
|
||||
}
|
||||
|
||||
//@Test
|
||||
//public void testShadowVariableError1() throws IOException {
|
||||
// compileAndCompare("shadow-variable-error-1.c");
|
||||
|
16
src/test/kc/labelgoto-0.c
Normal file
16
src/test/kc/labelgoto-0.c
Normal file
@ -0,0 +1,16 @@
|
||||
// Test labels/goto
|
||||
// a few simple labels
|
||||
|
||||
void main() {
|
||||
label1:
|
||||
char * const SCREEN = (char*)0x0400;
|
||||
label2:
|
||||
for(char i=0;i<10;i++) {
|
||||
label3:
|
||||
SCREEN[i] = i;
|
||||
label4:
|
||||
}
|
||||
label5:
|
||||
SCREEN[40] = '*';
|
||||
label6:
|
||||
}
|
8
src/test/kc/labelgoto-1.c
Normal file
8
src/test/kc/labelgoto-1.c
Normal file
@ -0,0 +1,8 @@
|
||||
// Test labels/goto
|
||||
// a duplicate label
|
||||
|
||||
void main() {
|
||||
label1:
|
||||
char * const SCREEN = (char*)0x0400;
|
||||
label1:
|
||||
}
|
10
src/test/kc/labelgoto-2.c
Normal file
10
src/test/kc/labelgoto-2.c
Normal file
@ -0,0 +1,10 @@
|
||||
// Test labels/goto
|
||||
// a simple goto a forward label
|
||||
|
||||
void main() {
|
||||
char * const SCREEN = (char*)0x0400;
|
||||
goto skip;
|
||||
SCREEN[0] = '*';
|
||||
skip:
|
||||
SCREEN[1] = '*';
|
||||
}
|
10
src/test/kc/labelgoto-3.c
Normal file
10
src/test/kc/labelgoto-3.c
Normal file
@ -0,0 +1,10 @@
|
||||
// Test labels/goto
|
||||
// an infinite loop using goto
|
||||
|
||||
void main() {
|
||||
char * const SCREEN = (char*)0x0400;
|
||||
char i=0;
|
||||
repeat:
|
||||
SCREEN[i++] = '*';
|
||||
goto repeat;
|
||||
}
|
8
src/test/kc/labelgoto-4.c
Normal file
8
src/test/kc/labelgoto-4.c
Normal file
@ -0,0 +1,8 @@
|
||||
// Test labels/goto
|
||||
// goto undefined label
|
||||
|
||||
void main() {
|
||||
char * const SCREEN = (char*)0x0400;
|
||||
goto skip;
|
||||
SCREEN[0] = '*';
|
||||
}
|
13
src/test/kc/labelgoto-5.c
Normal file
13
src/test/kc/labelgoto-5.c
Normal file
@ -0,0 +1,13 @@
|
||||
// Test labels/goto
|
||||
// goto a label nested in a loop
|
||||
|
||||
void main() {
|
||||
char * const SCREEN = (char*)0x0400;
|
||||
char i = 0;
|
||||
goto first;
|
||||
for(;i<10;i++) {
|
||||
SCREEN[i] = '*';
|
||||
first:
|
||||
SCREEN[40]++;
|
||||
}
|
||||
}
|
31
src/test/ref/labelgoto-0.asm
Normal file
31
src/test/ref/labelgoto-0.asm
Normal file
@ -0,0 +1,31 @@
|
||||
// Test labels/goto
|
||||
// a few simple labels
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-0.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
.segment Code
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
ldx #0
|
||||
__b1:
|
||||
// for(char i=0;i<10;i++)
|
||||
cpx #$a
|
||||
bcc label3
|
||||
// SCREEN[40] = '*'
|
||||
lda #'*'
|
||||
sta SCREEN+$28
|
||||
// }
|
||||
rts
|
||||
label3:
|
||||
// SCREEN[i] = i
|
||||
txa
|
||||
sta SCREEN,x
|
||||
// for(char i=0;i<10;i++)
|
||||
inx
|
||||
jmp __b1
|
||||
}
|
30
src/test/ref/labelgoto-0.cfg
Normal file
30
src/test/ref/labelgoto-0.cfg
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::label1
|
||||
main::label1: scope:[main] from main
|
||||
[1] phi()
|
||||
to:main::label2
|
||||
main::label2: scope:[main] from main::label1
|
||||
[2] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main::label2 main::label4
|
||||
[3] main::i#2 = phi( main::label2/0, main::label4/main::i#1 )
|
||||
[4] if(main::i#2<$a) goto main::label3
|
||||
to:main::label5
|
||||
main::label5: scope:[main] from main::@1
|
||||
[5] *(main::SCREEN+$28) = '*'
|
||||
to:main::label6
|
||||
main::label6: scope:[main] from main::label5
|
||||
[6] phi()
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::label6
|
||||
[7] return
|
||||
to:@return
|
||||
main::label3: scope:[main] from main::@1
|
||||
[8] main::SCREEN[main::i#2] = main::i#2
|
||||
to:main::label4
|
||||
main::label4: scope:[main] from main::label3
|
||||
[9] main::i#1 = ++ main::i#2
|
||||
to:main::@1
|
314
src/test/ref/labelgoto-0.log
Normal file
314
src/test/ref/labelgoto-0.log
Normal file
@ -0,0 +1,314 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
to:main::label1
|
||||
main::label1: scope:[main] from main
|
||||
to:main::label2
|
||||
main::label2: scope:[main] from main::label1
|
||||
main::i#0 = 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main::label2 main::label4
|
||||
main::i#2 = phi( main::label2/main::i#0, main::label4/main::i#1 )
|
||||
main::$0 = main::i#2 < $a
|
||||
if(main::$0) goto main::label3
|
||||
to:main::label5
|
||||
main::label3: scope:[main] from main::@1
|
||||
main::i#3 = phi( main::@1/main::i#2 )
|
||||
main::SCREEN[main::i#3] = main::i#3
|
||||
to:main::label4
|
||||
main::label4: scope:[main] from main::label3
|
||||
main::i#4 = phi( main::label3/main::i#3 )
|
||||
main::i#1 = ++ main::i#4
|
||||
to:main::@1
|
||||
main::label5: scope:[main] from main::@1
|
||||
main::SCREEN[$28] = '*'
|
||||
to:main::label6
|
||||
main::label6: scope:[main] from main::label5
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::label6
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
void __start()
|
||||
void main()
|
||||
bool~ main::$0
|
||||
constant byte* const main::SCREEN = (byte*)$400
|
||||
byte main::i
|
||||
byte main::i#0
|
||||
byte main::i#1
|
||||
byte main::i#2
|
||||
byte main::i#3
|
||||
byte main::i#4
|
||||
|
||||
Adding number conversion cast (unumber) $a in main::$0 = main::i#2 < $a
|
||||
Adding number conversion cast (unumber) $28 in main::SCREEN[$28] = '*'
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Simplifying constant integer cast $a
|
||||
Simplifying constant integer cast $28
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) $a
|
||||
Finalized unsigned number type (byte) $28
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias main::i#2 = main::i#3 main::i#4
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition main::$0 [3] if(main::i#2<$a) goto main::label3
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Removing unused procedure __start
|
||||
Removing unused procedure block __start
|
||||
Removing unused procedure block __start::@1
|
||||
Removing unused procedure block __start::@return
|
||||
Successful SSA optimization PassNEliminateEmptyStart
|
||||
Inlining constant with var siblings main::i#0
|
||||
Constant inlined main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Consolidated array index constant in *(main::SCREEN+$28)
|
||||
Successful SSA optimization Pass2ConstantAdditionElimination
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of main::label1
|
||||
Adding NOP phi() at start of main::label2
|
||||
Adding NOP phi() at start of main::label6
|
||||
CALL GRAPH
|
||||
|
||||
Created 1 initial phi equivalence classes
|
||||
Coalesced [10] main::i#5 = main::i#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of main::label1
|
||||
Adding NOP phi() at start of main::label2
|
||||
Adding NOP phi() at start of main::label6
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::label1
|
||||
main::label1: scope:[main] from main
|
||||
[1] phi()
|
||||
to:main::label2
|
||||
main::label2: scope:[main] from main::label1
|
||||
[2] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main::label2 main::label4
|
||||
[3] main::i#2 = phi( main::label2/0, main::label4/main::i#1 )
|
||||
[4] if(main::i#2<$a) goto main::label3
|
||||
to:main::label5
|
||||
main::label5: scope:[main] from main::@1
|
||||
[5] *(main::SCREEN+$28) = '*'
|
||||
to:main::label6
|
||||
main::label6: scope:[main] from main::label5
|
||||
[6] phi()
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::label6
|
||||
[7] return
|
||||
to:@return
|
||||
main::label3: scope:[main] from main::@1
|
||||
[8] main::SCREEN[main::i#2] = main::i#2
|
||||
to:main::label4
|
||||
main::label4: scope:[main] from main::label3
|
||||
[9] main::i#1 = ++ main::i#2
|
||||
to:main::@1
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
byte main::i
|
||||
byte main::i#1 22.0
|
||||
byte main::i#2 18.333333333333332
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [5] *(main::SCREEN+$28) = '*' [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 40.33: zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 326 combination reg byte x [ main::i#2 main::i#1 ]
|
||||
Uplifting [] best 326 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test labels/goto
|
||||
// a few simple labels
|
||||
// Upstart
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-0.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
// Global Constants & labels
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
// [1] phi from main to main::label1 [phi:main->main::label1]
|
||||
label1_from_main:
|
||||
jmp label1
|
||||
// main::label1
|
||||
label1:
|
||||
// [2] phi from main::label1 to main::label2 [phi:main::label1->main::label2]
|
||||
label2_from_label1:
|
||||
jmp label2
|
||||
// main::label2
|
||||
label2:
|
||||
// [3] phi from main::label2 to main::@1 [phi:main::label2->main::@1]
|
||||
__b1_from_label2:
|
||||
// [3] phi main::i#2 = 0 [phi:main::label2->main::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [4] if(main::i#2<$a) goto main::label3 -- vbuxx_lt_vbuc1_then_la1
|
||||
cpx #$a
|
||||
bcc label3
|
||||
jmp label5
|
||||
// main::label5
|
||||
label5:
|
||||
// [5] *(main::SCREEN+$28) = '*' -- _deref_pbuc1=vbuc2
|
||||
lda #'*'
|
||||
sta SCREEN+$28
|
||||
// [6] phi from main::label5 to main::label6 [phi:main::label5->main::label6]
|
||||
label6_from_label5:
|
||||
jmp label6
|
||||
// main::label6
|
||||
label6:
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [7] return
|
||||
rts
|
||||
// main::label3
|
||||
label3:
|
||||
// [8] main::SCREEN[main::i#2] = main::i#2 -- pbuc1_derefidx_vbuxx=vbuxx
|
||||
txa
|
||||
sta SCREEN,x
|
||||
jmp label4
|
||||
// main::label4
|
||||
label4:
|
||||
// [9] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [3] phi from main::label4 to main::@1 [phi:main::label4->main::@1]
|
||||
__b1_from_label4:
|
||||
// [3] phi main::i#2 = main::i#1 [phi:main::label4->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp label1
|
||||
Removing instruction jmp label2
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp label5
|
||||
Removing instruction jmp label6
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp label4
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction label1_from_main:
|
||||
Removing instruction label1:
|
||||
Removing instruction label2_from_label1:
|
||||
Removing instruction __b1_from_label2:
|
||||
Removing instruction label6_from_label5:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction label2:
|
||||
Removing instruction label5:
|
||||
Removing instruction label6:
|
||||
Removing instruction label4:
|
||||
Removing instruction __b1_from_label4:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
void main()
|
||||
constant byte* const main::SCREEN = (byte*) 1024
|
||||
byte main::i
|
||||
byte main::i#1 reg byte x 22.0
|
||||
byte main::i#2 reg byte x 18.333333333333332
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 197
|
||||
|
||||
// File Comments
|
||||
// Test labels/goto
|
||||
// a few simple labels
|
||||
// Upstart
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-0.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
// Global Constants & labels
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
// [1] phi from main to main::label1 [phi:main->main::label1]
|
||||
// main::label1
|
||||
// [2] phi from main::label1 to main::label2 [phi:main::label1->main::label2]
|
||||
// main::label2
|
||||
// [3] phi from main::label2 to main::@1 [phi:main::label2->main::@1]
|
||||
// [3] phi main::i#2 = 0 [phi:main::label2->main::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
// main::@1
|
||||
__b1:
|
||||
// for(char i=0;i<10;i++)
|
||||
// [4] if(main::i#2<$a) goto main::label3 -- vbuxx_lt_vbuc1_then_la1
|
||||
cpx #$a
|
||||
bcc label3
|
||||
// main::label5
|
||||
// SCREEN[40] = '*'
|
||||
// [5] *(main::SCREEN+$28) = '*' -- _deref_pbuc1=vbuc2
|
||||
lda #'*'
|
||||
sta SCREEN+$28
|
||||
// [6] phi from main::label5 to main::label6 [phi:main::label5->main::label6]
|
||||
// main::label6
|
||||
// main::@return
|
||||
// }
|
||||
// [7] return
|
||||
rts
|
||||
// main::label3
|
||||
label3:
|
||||
// SCREEN[i] = i
|
||||
// [8] main::SCREEN[main::i#2] = main::i#2 -- pbuc1_derefidx_vbuxx=vbuxx
|
||||
txa
|
||||
sta SCREEN,x
|
||||
// main::label4
|
||||
// for(char i=0;i<10;i++)
|
||||
// [9] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [3] phi from main::label4 to main::@1 [phi:main::label4->main::@1]
|
||||
// [3] phi main::i#2 = main::i#1 [phi:main::label4->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
7
src/test/ref/labelgoto-0.sym
Normal file
7
src/test/ref/labelgoto-0.sym
Normal file
@ -0,0 +1,7 @@
|
||||
void main()
|
||||
constant byte* const main::SCREEN = (byte*) 1024
|
||||
byte main::i
|
||||
byte main::i#1 reg byte x 22.0
|
||||
byte main::i#2 reg byte x 18.333333333333332
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
19
src/test/ref/labelgoto-2.asm
Normal file
19
src/test/ref/labelgoto-2.asm
Normal file
@ -0,0 +1,19 @@
|
||||
// Test labels/goto
|
||||
// a simple goto a forward label
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-2.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
.segment Code
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
// SCREEN[1] = '*'
|
||||
lda #'*'
|
||||
sta SCREEN+1
|
||||
// }
|
||||
rts
|
||||
}
|
11
src/test/ref/labelgoto-2.cfg
Normal file
11
src/test/ref/labelgoto-2.cfg
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::skip
|
||||
main::skip: scope:[main] from main
|
||||
[1] *(main::SCREEN+1) = '*'
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::skip
|
||||
[2] return
|
||||
to:@return
|
166
src/test/ref/labelgoto-2.log
Normal file
166
src/test/ref/labelgoto-2.log
Normal file
@ -0,0 +1,166 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
to:main::skip
|
||||
main::skip: scope:[main] from main main::@1
|
||||
main::SCREEN[1] = '*'
|
||||
to:main::@return
|
||||
main::@1: scope:[main] from
|
||||
main::SCREEN[0] = '*'
|
||||
to:main::skip
|
||||
main::@return: scope:[main] from main::skip
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
void __start()
|
||||
void main()
|
||||
constant byte* const main::SCREEN = (byte*)$400
|
||||
|
||||
Adding number conversion cast (unumber) 1 in main::SCREEN[1] = '*'
|
||||
Adding number conversion cast (unumber) 0 in main::SCREEN[0] = '*'
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Simplifying constant integer cast 1
|
||||
Simplifying constant integer cast 0
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) 1
|
||||
Finalized unsigned number type (byte) 0
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Simplifying expression containing zero main::SCREEN in [1] main::SCREEN[0] = '*'
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Removing unused block main::@1
|
||||
Successful SSA optimization Pass2EliminateUnusedBlocks
|
||||
Removing unused procedure __start
|
||||
Removing unused procedure block __start
|
||||
Removing unused procedure block __start::@1
|
||||
Removing unused procedure block __start::@return
|
||||
Successful SSA optimization PassNEliminateEmptyStart
|
||||
Consolidated array index constant in *(main::SCREEN+1)
|
||||
Successful SSA optimization Pass2ConstantAdditionElimination
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::skip
|
||||
main::skip: scope:[main] from main
|
||||
[1] *(main::SCREEN+1) = '*'
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::skip
|
||||
[2] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [1] *(main::SCREEN+1) = '*' [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 45 combination
|
||||
Uplifting [] best 45 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test labels/goto
|
||||
// a simple goto a forward label
|
||||
// Upstart
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-2.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
// Global Constants & labels
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
jmp skip
|
||||
// main::skip
|
||||
skip:
|
||||
// [1] *(main::SCREEN+1) = '*' -- _deref_pbuc1=vbuc2
|
||||
lda #'*'
|
||||
sta SCREEN+1
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [2] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp skip
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction skip:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
void main()
|
||||
constant byte* const main::SCREEN = (byte*) 1024
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 12
|
||||
|
||||
// File Comments
|
||||
// Test labels/goto
|
||||
// a simple goto a forward label
|
||||
// Upstart
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-2.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
// Global Constants & labels
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
// main::skip
|
||||
// SCREEN[1] = '*'
|
||||
// [1] *(main::SCREEN+1) = '*' -- _deref_pbuc1=vbuc2
|
||||
lda #'*'
|
||||
sta SCREEN+1
|
||||
// main::@return
|
||||
// }
|
||||
// [2] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
3
src/test/ref/labelgoto-2.sym
Normal file
3
src/test/ref/labelgoto-2.sym
Normal file
@ -0,0 +1,3 @@
|
||||
void main()
|
||||
constant byte* const main::SCREEN = (byte*) 1024
|
||||
|
22
src/test/ref/labelgoto-3.asm
Normal file
22
src/test/ref/labelgoto-3.asm
Normal file
@ -0,0 +1,22 @@
|
||||
// Test labels/goto
|
||||
// an infinite loop using goto
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-3.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
.segment Code
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
ldx #0
|
||||
repeat:
|
||||
// SCREEN[i++] = '*'
|
||||
lda #'*'
|
||||
sta SCREEN,x
|
||||
// SCREEN[i++] = '*';
|
||||
inx
|
||||
jmp repeat
|
||||
}
|
10
src/test/ref/labelgoto-3.cfg
Normal file
10
src/test/ref/labelgoto-3.cfg
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::repeat
|
||||
main::repeat: scope:[main] from main main::repeat
|
||||
[1] main::i#2 = phi( main/0, main::repeat/main::i#1 )
|
||||
[2] main::SCREEN[main::i#2] = '*'
|
||||
[3] main::i#1 = ++ main::i#2
|
||||
to:main::repeat
|
186
src/test/ref/labelgoto-3.log
Normal file
186
src/test/ref/labelgoto-3.log
Normal file
@ -0,0 +1,186 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
main::i#0 = 0
|
||||
to:main::repeat
|
||||
main::repeat: scope:[main] from main main::repeat
|
||||
main::i#2 = phi( main/main::i#0, main::repeat/main::i#1 )
|
||||
main::SCREEN[main::i#2] = '*'
|
||||
main::i#1 = ++ main::i#2
|
||||
to:main::repeat
|
||||
main::@return: scope:[main] from
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
void __start()
|
||||
void main()
|
||||
constant byte* const main::SCREEN = (byte*)$400
|
||||
byte main::i
|
||||
byte main::i#0
|
||||
byte main::i#1
|
||||
byte main::i#2
|
||||
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Constant main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Removing unused block main::@return
|
||||
Successful SSA optimization Pass2EliminateUnusedBlocks
|
||||
Removing unused procedure __start
|
||||
Removing unused procedure block __start
|
||||
Removing unused procedure block __start::@1
|
||||
Removing unused procedure block __start::@return
|
||||
Successful SSA optimization PassNEliminateEmptyStart
|
||||
Inlining constant with var siblings main::i#0
|
||||
Constant inlined main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
|
||||
Created 1 initial phi equivalence classes
|
||||
Coalesced [4] main::i#3 = main::i#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::repeat
|
||||
main::repeat: scope:[main] from main main::repeat
|
||||
[1] main::i#2 = phi( main/0, main::repeat/main::i#1 )
|
||||
[2] main::SCREEN[main::i#2] = '*'
|
||||
[3] main::i#1 = ++ main::i#2
|
||||
to:main::repeat
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
byte main::i
|
||||
byte main::i#1 22.0
|
||||
byte main::i#2 16.5
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [2] main::SCREEN[main::i#2] = '*' [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
Statement [2] main::SCREEN[main::i#2] = '*' [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
|
||||
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 38.5: zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 170 combination reg byte x [ main::i#2 main::i#1 ]
|
||||
Uplifting [] best 170 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test labels/goto
|
||||
// an infinite loop using goto
|
||||
// Upstart
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-3.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
// Global Constants & labels
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
// [1] phi from main to main::repeat [phi:main->main::repeat]
|
||||
repeat_from_main:
|
||||
// [1] phi main::i#2 = 0 [phi:main->main::repeat#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
jmp repeat
|
||||
// main::repeat
|
||||
repeat:
|
||||
// [2] main::SCREEN[main::i#2] = '*' -- pbuc1_derefidx_vbuxx=vbuc2
|
||||
lda #'*'
|
||||
sta SCREEN,x
|
||||
// [3] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [1] phi from main::repeat to main::repeat [phi:main::repeat->main::repeat]
|
||||
repeat_from_repeat:
|
||||
// [1] phi main::i#2 = main::i#1 [phi:main::repeat->main::repeat#0] -- register_copy
|
||||
jmp repeat
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp repeat
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction repeat_from_main:
|
||||
Removing instruction repeat_from_repeat:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
void main()
|
||||
constant byte* const main::SCREEN = (byte*) 1024
|
||||
byte main::i
|
||||
byte main::i#1 reg byte x 22.0
|
||||
byte main::i#2 reg byte x 16.5
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 140
|
||||
|
||||
// File Comments
|
||||
// Test labels/goto
|
||||
// an infinite loop using goto
|
||||
// Upstart
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-3.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
// Global Constants & labels
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
// [1] phi from main to main::repeat [phi:main->main::repeat]
|
||||
// [1] phi main::i#2 = 0 [phi:main->main::repeat#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
// main::repeat
|
||||
repeat:
|
||||
// SCREEN[i++] = '*'
|
||||
// [2] main::SCREEN[main::i#2] = '*' -- pbuc1_derefidx_vbuxx=vbuc2
|
||||
lda #'*'
|
||||
sta SCREEN,x
|
||||
// SCREEN[i++] = '*';
|
||||
// [3] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [1] phi from main::repeat to main::repeat [phi:main::repeat->main::repeat]
|
||||
// [1] phi main::i#2 = main::i#1 [phi:main::repeat->main::repeat#0] -- register_copy
|
||||
jmp repeat
|
||||
}
|
||||
// File Data
|
||||
|
7
src/test/ref/labelgoto-3.sym
Normal file
7
src/test/ref/labelgoto-3.sym
Normal file
@ -0,0 +1,7 @@
|
||||
void main()
|
||||
constant byte* const main::SCREEN = (byte*) 1024
|
||||
byte main::i
|
||||
byte main::i#1 reg byte x 22.0
|
||||
byte main::i#2 reg byte x 16.5
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
29
src/test/ref/labelgoto-5.asm
Normal file
29
src/test/ref/labelgoto-5.asm
Normal file
@ -0,0 +1,29 @@
|
||||
// Test labels/goto
|
||||
// goto a nested label
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-5.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
.segment Code
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
ldx #0
|
||||
first:
|
||||
// SCREEN[40]++;
|
||||
inc SCREEN+$28
|
||||
// for(;i<10;i++)
|
||||
inx
|
||||
cpx #$a
|
||||
bcc __b2
|
||||
// }
|
||||
rts
|
||||
__b2:
|
||||
// SCREEN[i] = '*'
|
||||
lda #'*'
|
||||
sta SCREEN,x
|
||||
jmp first
|
||||
}
|
19
src/test/ref/labelgoto-5.cfg
Normal file
19
src/test/ref/labelgoto-5.cfg
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::first
|
||||
main::first: scope:[main] from main main::@2
|
||||
[1] main::i#2 = phi( main/0, main::@2/main::i#1 )
|
||||
[2] *(main::SCREEN+$28) = ++ *(main::SCREEN+$28)
|
||||
[3] main::i#1 = ++ main::i#2
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main::first
|
||||
[4] if(main::i#1<$a) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[5] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[6] main::SCREEN[main::i#1] = '*'
|
||||
to:main::first
|
543
src/test/ref/labelgoto-5.log
Normal file
543
src/test/ref/labelgoto-5.log
Normal file
@ -0,0 +1,543 @@
|
||||
PARSING /Users/jespergravgaard/c64/kickc/src/test/kc/labelgoto-5.c
|
||||
// Test labels/goto
|
||||
// goto a nested label
|
||||
|
||||
void main() {
|
||||
char * const SCREEN = (char*)0x0400;
|
||||
char i = 0;
|
||||
goto first;
|
||||
for(;i<10;i++) {
|
||||
SCREEN[i] = '*';
|
||||
first:
|
||||
SCREEN[40]++;
|
||||
}
|
||||
}
|
||||
Adding pre/post-modifier main::SCREEN[$28] = ++ main::SCREEN[$28]
|
||||
Adding pre/post-modifier main::i = ++ main::i
|
||||
FIRST CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
main::i = 0
|
||||
to:main::first
|
||||
main::first: scope:[main] from main main:::1::@2
|
||||
main:::1::$1 = main::SCREEN[$28]
|
||||
main::SCREEN[$28] = ++ main::SCREEN[$28]
|
||||
main::i = ++ main::i
|
||||
to:main:::1::@1
|
||||
main::@1: scope:[main] from
|
||||
to:main:::1::@1
|
||||
main:::1::@1: scope:[main] from main::@1 main::first
|
||||
main:::1::$0 = main::i < $a
|
||||
if(main:::1::$0) goto main:::1::@2
|
||||
to:main:::1::@4
|
||||
main:::1::@2: scope:[main] from main:::1::@1 main:::1::@5
|
||||
main::SCREEN[main::i] = '*'
|
||||
to:main::first
|
||||
main:::1::@4: scope:[main] from main:::1::@1
|
||||
to:main:::1::@3
|
||||
main:::1::@3: scope:[main] from main:::1::@4 main::@2
|
||||
to:main::@return
|
||||
main:::1::@5: scope:[main] from
|
||||
to:main:::1::@2
|
||||
main::@2: scope:[main] from
|
||||
to:main:::1::@3
|
||||
main::@return: scope:[main] from main:::1::@3
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOLS
|
||||
void __start()
|
||||
void main()
|
||||
bool~ main::$0
|
||||
byte~ main::$1
|
||||
constant byte* const main::SCREEN = (byte*)$400
|
||||
byte main::i
|
||||
|
||||
CONTROL FLOW GRAPH BEFORE SIZEOF FIX
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
main::i = 0
|
||||
to:main::first
|
||||
main::first: scope:[main] from main main::@4
|
||||
main::$1 = main::SCREEN[$28]
|
||||
main::SCREEN[$28] = ++ main::SCREEN[$28]
|
||||
main::i = ++ main::i
|
||||
to:main::@3
|
||||
main::@1: scope:[main] from
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::first
|
||||
main::$0 = main::i < $a
|
||||
if(main::$0) goto main::@4
|
||||
to:main::@6
|
||||
main::@4: scope:[main] from main::@3 main::@7
|
||||
main::SCREEN[main::i] = '*'
|
||||
to:main::first
|
||||
main::@6: scope:[main] from main::@3
|
||||
to:main::@5
|
||||
main::@5: scope:[main] from main::@2 main::@6
|
||||
to:main::@return
|
||||
main::@7: scope:[main] from
|
||||
to:main::@4
|
||||
main::@2: scope:[main] from
|
||||
to:main::@5
|
||||
main::@return: scope:[main] from main::@5
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start
|
||||
return
|
||||
to:@return
|
||||
|
||||
CONTROL FLOW GRAPH AFTER UNWIND
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
main::i = 0
|
||||
to:main::first
|
||||
main::first: scope:[main] from main main::@4
|
||||
main::$1 = main::SCREEN[$28]
|
||||
main::SCREEN[$28] = ++ main::SCREEN[$28]
|
||||
main::i = ++ main::i
|
||||
to:main::@3
|
||||
main::@1: scope:[main] from
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::first
|
||||
main::$0 = main::i < $a
|
||||
if(main::$0) goto main::@4
|
||||
to:main::@6
|
||||
main::@4: scope:[main] from main::@3 main::@7
|
||||
main::SCREEN[main::i] = '*'
|
||||
to:main::first
|
||||
main::@6: scope:[main] from main::@3
|
||||
to:main::@5
|
||||
main::@5: scope:[main] from main::@2 main::@6
|
||||
to:main::@return
|
||||
main::@7: scope:[main] from
|
||||
to:main::@4
|
||||
main::@2: scope:[main] from
|
||||
to:main::@5
|
||||
main::@return: scope:[main] from main::@5
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start
|
||||
return
|
||||
to:@return
|
||||
|
||||
CONTROL FLOW GRAPH BEFORE INLINING
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
main::i = 0
|
||||
to:main::first
|
||||
main::first: scope:[main] from main main::@4
|
||||
main::$1 = main::SCREEN[$28]
|
||||
main::SCREEN[$28] = ++ main::SCREEN[$28]
|
||||
main::i = ++ main::i
|
||||
to:main::@3
|
||||
main::@1: scope:[main] from
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::first
|
||||
main::$0 = main::i < $a
|
||||
if(main::$0) goto main::@4
|
||||
to:main::@6
|
||||
main::@4: scope:[main] from main::@3 main::@7
|
||||
main::SCREEN[main::i] = '*'
|
||||
to:main::first
|
||||
main::@6: scope:[main] from main::@3
|
||||
to:main::@5
|
||||
main::@5: scope:[main] from main::@2 main::@6
|
||||
to:main::@return
|
||||
main::@7: scope:[main] from
|
||||
to:main::@4
|
||||
main::@2: scope:[main] from
|
||||
to:main::@5
|
||||
main::@return: scope:[main] from main::@5
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start
|
||||
return
|
||||
to:@return
|
||||
|
||||
INITIAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] main::i = 0
|
||||
to:main::first
|
||||
main::first: scope:[main] from main main::@4
|
||||
[1] main::$1 = main::SCREEN[$28]
|
||||
[2] main::SCREEN[$28] = ++ main::SCREEN[$28]
|
||||
[3] main::i = ++ main::i
|
||||
to:main::@3
|
||||
main::@1: scope:[main] from
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::first
|
||||
[4] main::$0 = main::i < $a
|
||||
[5] if(main::$0) goto main::@4
|
||||
to:main::@6
|
||||
main::@4: scope:[main] from main::@3 main::@7
|
||||
[6] main::SCREEN[main::i] = '*'
|
||||
to:main::first
|
||||
main::@6: scope:[main] from main::@3
|
||||
to:main::@5
|
||||
main::@5: scope:[main] from main::@2 main::@6
|
||||
to:main::@return
|
||||
main::@7: scope:[main] from
|
||||
to:main::@4
|
||||
main::@2: scope:[main] from
|
||||
to:main::@5
|
||||
main::@return: scope:[main] from main::@5
|
||||
[7] return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
[8] call main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start
|
||||
[9] return
|
||||
to:@return
|
||||
|
||||
Eliminating unused variable main::$1 and assignment [1] main::$1 = main::SCREEN[$28]
|
||||
PROCEDURE MODIFY VARIABLE ANALYSIS
|
||||
|
||||
PROCEDURE CALLS
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
main::i = 0
|
||||
to:main::first
|
||||
main::first: scope:[main] from main main::@2
|
||||
main::SCREEN[$28] = ++ main::SCREEN[$28]
|
||||
main::i = ++ main::i
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main::first
|
||||
main::$0 = main::i < $a
|
||||
if(main::$0) goto main::@2
|
||||
to:main::@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
main::SCREEN[main::i] = '*'
|
||||
to:main::first
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start
|
||||
return
|
||||
to:@return
|
||||
|
||||
PROCEDURE PARAMETERS
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
main::i = 0
|
||||
to:main::first
|
||||
main::first: scope:[main] from main main::@2
|
||||
main::SCREEN[$28] = ++ main::SCREEN[$28]
|
||||
main::i = ++ main::i
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main::first
|
||||
main::$0 = main::i < $a
|
||||
if(main::$0) goto main::@2
|
||||
to:main::@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
main::SCREEN[main::i] = '*'
|
||||
to:main::first
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
Completing Phi functions...
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
main::i#0 = 0
|
||||
to:main::first
|
||||
main::first: scope:[main] from main main::@2
|
||||
main::i#2 = phi( main/main::i#0, main::@2/main::i#4 )
|
||||
main::SCREEN[$28] = ++ main::SCREEN[$28]
|
||||
main::i#1 = ++ main::i#2
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main::first
|
||||
main::i#3 = phi( main::first/main::i#1 )
|
||||
main::$0 = main::i#3 < $a
|
||||
if(main::$0) goto main::@2
|
||||
to:main::@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
main::i#4 = phi( main::@1/main::i#3 )
|
||||
main::SCREEN[main::i#4] = '*'
|
||||
to:main::first
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
void __start()
|
||||
void main()
|
||||
bool~ main::$0
|
||||
constant byte* const main::SCREEN = (byte*)$400
|
||||
byte main::i
|
||||
byte main::i#0
|
||||
byte main::i#1
|
||||
byte main::i#2
|
||||
byte main::i#3
|
||||
byte main::i#4
|
||||
|
||||
Adding number conversion cast (unumber) $28 in main::SCREEN[$28] = ++ main::SCREEN[$28]
|
||||
Adding number conversion cast (unumber) $28 in main::SCREEN[$28] = ++ main::SCREEN[(unumber)$28]
|
||||
Adding number conversion cast (unumber) $a in main::$0 = main::i#3 < $a
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Simplifying constant integer cast $28
|
||||
Simplifying constant integer cast $28
|
||||
Simplifying constant integer cast $a
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) $28
|
||||
Finalized unsigned number type (byte) $28
|
||||
Finalized unsigned number type (byte) $a
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias main::i#1 = main::i#3 main::i#4
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition main::$0 [5] if(main::i#1<$a) goto main::@2
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Removing unused procedure __start
|
||||
Removing unused procedure block __start
|
||||
Removing unused procedure block __start::@1
|
||||
Removing unused procedure block __start::@return
|
||||
Successful SSA optimization PassNEliminateEmptyStart
|
||||
Inlining constant with var siblings main::i#0
|
||||
Constant inlined main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Consolidated array index constant in *(main::SCREEN+$28)
|
||||
Consolidated array index constant in *(main::SCREEN+$28)
|
||||
Successful SSA optimization Pass2ConstantAdditionElimination
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
|
||||
Created 1 initial phi equivalence classes
|
||||
Coalesced [7] main::i#5 = main::i#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::first
|
||||
main::first: scope:[main] from main main::@2
|
||||
[1] main::i#2 = phi( main/0, main::@2/main::i#1 )
|
||||
[2] *(main::SCREEN+$28) = ++ *(main::SCREEN+$28)
|
||||
[3] main::i#1 = ++ main::i#2
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main::first
|
||||
[4] if(main::i#1<$a) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[5] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[6] main::SCREEN[main::i#1] = '*'
|
||||
to:main::first
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
byte main::i
|
||||
byte main::i#1 14.666666666666666
|
||||
byte main::i#2 11.0
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [6] main::SCREEN[main::i#1] = '*' [ main::i#1 ] ( [ main::i#1 ] { } ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
Statement [6] main::SCREEN[main::i#1] = '*' [ main::i#1 ] ( [ main::i#1 ] { } ) always clobbers reg byte a
|
||||
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 25.67: zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 341 combination reg byte x [ main::i#2 main::i#1 ]
|
||||
Uplifting [] best 341 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test labels/goto
|
||||
// goto a nested label
|
||||
// Upstart
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-5.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
// Global Constants & labels
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
// [1] phi from main to main::first [phi:main->main::first]
|
||||
first_from_main:
|
||||
// [1] phi main::i#2 = 0 [phi:main->main::first#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
jmp first
|
||||
// main::first
|
||||
first:
|
||||
// [2] *(main::SCREEN+$28) = ++ *(main::SCREEN+$28) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc SCREEN+$28
|
||||
// [3] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [4] if(main::i#1<$a) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
|
||||
cpx #$a
|
||||
bcc __b2
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [5] return
|
||||
rts
|
||||
// main::@2
|
||||
__b2:
|
||||
// [6] main::SCREEN[main::i#1] = '*' -- pbuc1_derefidx_vbuxx=vbuc2
|
||||
lda #'*'
|
||||
sta SCREEN,x
|
||||
// [1] phi from main::@2 to main::first [phi:main::@2->main::first]
|
||||
first_from___b2:
|
||||
// [1] phi main::i#2 = main::i#1 [phi:main::@2->main::first#0] -- register_copy
|
||||
jmp first
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp first
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction first_from_main:
|
||||
Removing instruction __b1:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction first_from___b2:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
void main()
|
||||
constant byte* const main::SCREEN = (byte*) 1024
|
||||
byte main::i
|
||||
byte main::i#1 reg byte x 14.666666666666666
|
||||
byte main::i#2 reg byte x 11.0
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 251
|
||||
|
||||
// File Comments
|
||||
// Test labels/goto
|
||||
// goto a nested label
|
||||
// Upstart
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="labelgoto-5.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
// Global Constants & labels
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
// [1] phi from main to main::first [phi:main->main::first]
|
||||
// [1] phi main::i#2 = 0 [phi:main->main::first#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
// main::first
|
||||
first:
|
||||
// SCREEN[40]++;
|
||||
// [2] *(main::SCREEN+$28) = ++ *(main::SCREEN+$28) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc SCREEN+$28
|
||||
// for(;i<10;i++)
|
||||
// [3] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// main::@1
|
||||
// [4] if(main::i#1<$a) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
|
||||
cpx #$a
|
||||
bcc __b2
|
||||
// main::@return
|
||||
// }
|
||||
// [5] return
|
||||
rts
|
||||
// main::@2
|
||||
__b2:
|
||||
// SCREEN[i] = '*'
|
||||
// [6] main::SCREEN[main::i#1] = '*' -- pbuc1_derefidx_vbuxx=vbuc2
|
||||
lda #'*'
|
||||
sta SCREEN,x
|
||||
// [1] phi from main::@2 to main::first [phi:main::@2->main::first]
|
||||
// [1] phi main::i#2 = main::i#1 [phi:main::@2->main::first#0] -- register_copy
|
||||
jmp first
|
||||
}
|
||||
// File Data
|
||||
|
7
src/test/ref/labelgoto-5.sym
Normal file
7
src/test/ref/labelgoto-5.sym
Normal file
@ -0,0 +1,7 @@
|
||||
void main()
|
||||
constant byte* const main::SCREEN = (byte*) 1024
|
||||
byte main::i
|
||||
byte main::i#1 reg byte x 14.666666666666666
|
||||
byte main::i#2 reg byte x 11.0
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
Loading…
x
Reference in New Issue
Block a user