1
0
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:
jespergravgaard 2021-08-07 17:05:09 +02:00
parent 5ee8749d06
commit 1deb381c57
39 changed files with 3344 additions and 1954 deletions

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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}
*

View File

@ -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}
*

View File

@ -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

View File

@ -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

View File

@ -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
;

View File

@ -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()) {

View File

@ -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;
}
}

View File

@ -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
View 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:
}

View 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
View 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
View 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;
}

View 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
View 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]++;
}
}

View 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
}

View 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

View 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

View 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 ]

View 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
}

View 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

View 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

View File

@ -0,0 +1,3 @@
void main()
constant byte* const main::SCREEN = (byte*) 1024

View 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
}

View 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

View 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

View 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 ]

View 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
}

View 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

View 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

View 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 ]