1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-04-08 14:37:40 +00:00

Added support for declaring var-length parameter lists in functions. Added __intrinsic directive for specifying that a function is implemented in the compiler. Added initial tiny implementation of intrinsic printf(), which only handles %s. #410 #415

This commit is contained in:
jespergravgaard 2020-04-19 23:29:37 +02:00
parent 9c6e67ddc5
commit 9fa2e5d734
30 changed files with 3487 additions and 1912 deletions

View File

@ -255,6 +255,7 @@ public class Compiler {
new PassNTypeInference(program).execute();
new PassNTypeIdSimplification(program).execute();
new Pass1StructTypeSizeFix(program).execute();
new Pass1PrintfIntrinsicRewrite(program).execute();
new Pass1AssertReturn(program).execute();
new Pass1AssertUsedVars(program).execute();
new Pass1AssertNoModifyVars(program).execute();

View File

@ -27,6 +27,10 @@ public interface Directive {
class Inline implements Directive {
}
/** Function declared intrinsic. */
class Intrinsic implements Directive {
}
/** Variable declared as extern. */
class Extern implements Directive {
}

View File

@ -5,10 +5,9 @@ import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.passes.Pass1PrintfIntrinsicRewrite;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.*;
/** Symbol describing a procedure/function */
public class Procedure extends Scope {
@ -17,6 +16,8 @@ public class Procedure extends Scope {
private final SymbolType returnType;
/** The names of the parameters of the procedure. */
private List<String> parameterNames;
/** True if the parameter list ends with a variable length parameter list "..." */
private boolean variableLengthParameterList;
/** true if the procedure is declared inline. */
private boolean declaredInline;
/** The type of interrupt that the procedure serves. Null for all procedures not serving an interrupt. */
@ -27,6 +28,11 @@ public class Procedure extends Scope {
private List<Integer> reservedZps;
/** The code segment to put the procedure into. */
private String codeSegment;
/** True if the procedure is declared intrinsic. */
private boolean declaredIntrinsic;
/** The names of all legal intrinsic procedures. */
final public static List<String> INTRINSIC_PROCEDURES = Collections.singletonList(Pass1PrintfIntrinsicRewrite.INTRINSIC_PRINTF_NAME);
/** The method for passing parameters and return value to the procedure. */
public enum CallingConvention {
@ -85,6 +91,22 @@ public class Procedure extends Scope {
return parameterNames;
}
public void setVariableLengthParameterList(boolean variableLengthParameterList) {
this.variableLengthParameterList = variableLengthParameterList;
}
public boolean isVariableLengthParameterList() {
return variableLengthParameterList;
}
public boolean isDeclaredIntrinsic() {
return declaredIntrinsic;
}
public void setDeclaredIntrinsic(boolean declaredIntrinsic) {
this.declaredIntrinsic = declaredIntrinsic;
}
public Label getLabel() {
return new Label(getFullName(), getScope(), false);
}
@ -192,7 +214,6 @@ public class Procedure extends Scope {
}
@Override
public String toString() {
return toString(null);
@ -204,6 +225,9 @@ public class Procedure extends Scope {
if(declaredInline) {
res.append("inline ");
}
if(declaredIntrinsic) {
res.append("__intrinsic ");
}
if(!callingConvention.equals(CallingConvention.PHI_CALL)) {
res.append(getCallingConvention().getName()).append(" ");
}
@ -221,6 +245,9 @@ public class Procedure extends Scope {
res.append(parameter.toString(program));
}
}
if(isVariableLengthParameterList()) {
res.append(", ...");
}
res.append(")");
return res.toString();
}

View File

@ -32,6 +32,7 @@ SEMICOLON: ';' ;
COLON: ':';
COMMA: ',' ;
RANGE : '..' ;
PARAM_LIST : '...' ;
CONDITION : '?' ;
DOT : '.' ;
ARROW : '->' ;
@ -83,6 +84,7 @@ ADDRESS_ZEROPAGE: '__zp' ;
ADDRESS_MAINMEM: '__mem' ;
FORM_SSA: '__ssa' ;
FORM_MA: '__ma' ;
INTRINSIC: '__intrinsic' ;
CALLING: 'calling';
CALLINGCONVENTION: '__stackcall' | '__phicall' ;
VARMODEL: 'var_model';

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -9,231 +9,235 @@ SEMICOLON=8
COLON=9
COMMA=10
RANGE=11
CONDITION=12
DOT=13
ARROW=14
PLUS=15
MINUS=16
ASTERISK=17
DIVIDE=18
MODULO=19
INC=20
DEC=21
AND=22
BIT_NOT=23
BIT_XOR=24
BIT_OR=25
SHIFT_LEFT=26
SHIFT_RIGHT=27
EQUAL=28
NOT_EQUAL=29
LESS_THAN=30
LESS_THAN_EQUAL=31
GREATER_THAN_EQUAL=32
GREATER_THAN=33
LOGIC_AND=34
LOGIC_OR=35
ASSIGN=36
ASSIGN_COMPOUND=37
TYPEDEF=38
RESERVE=39
PC=40
TARGET=41
LINK=42
CPU=43
CODESEG=44
DATASEG=45
ENCODING=46
CONST=47
EXTERN=48
EXPORT=49
ALIGN=50
INLINE=51
VOLATILE=52
STATIC=53
INTERRUPT=54
REGISTER=55
ADDRESS=56
ADDRESS_ZEROPAGE=57
ADDRESS_MAINMEM=58
FORM_SSA=59
FORM_MA=60
CALLING=61
CALLINGCONVENTION=62
VARMODEL=63
IF=64
ELSE=65
WHILE=66
DO=67
FOR=68
SWITCH=69
RETURN=70
BREAK=71
CONTINUE=72
ASM=73
DEFAULT=74
CASE=75
STRUCT=76
ENUM=77
SIZEOF=78
TYPEID=79
DEFINED=80
KICKASM=81
RESOURCE=82
USES=83
CLOBBERS=84
BYTES=85
CYCLES=86
LOGIC_NOT=87
SIGNEDNESS=88
SIMPLETYPE=89
BOOLEAN=90
KICKASM_BODY=91
IMPORT=92
INCLUDE=93
PRAGMA=94
DEFINE=95
DEFINE_CONTINUE=96
UNDEF=97
IFDEF=98
IFNDEF=99
IFIF=100
ELIF=101
IFELSE=102
ENDIF=103
NUMBER=104
NUMFLOAT=105
BINFLOAT=106
DECFLOAT=107
HEXFLOAT=108
NUMINT=109
BININTEGER=110
DECINTEGER=111
HEXINTEGER=112
NAME=113
STRING=114
CHAR=115
WS=116
COMMENT_LINE=117
COMMENT_BLOCK=118
ASM_BYTE=119
ASM_MNEMONIC=120
ASM_IMM=121
ASM_COLON=122
ASM_COMMA=123
ASM_PAR_BEGIN=124
ASM_PAR_END=125
ASM_BRACKET_BEGIN=126
ASM_BRACKET_END=127
ASM_DOT=128
ASM_SHIFT_LEFT=129
ASM_SHIFT_RIGHT=130
ASM_PLUS=131
ASM_MINUS=132
ASM_LESS_THAN=133
ASM_GREATER_THAN=134
ASM_MULTIPLY=135
ASM_DIVIDE=136
ASM_CURLY_BEGIN=137
ASM_CURLY_END=138
ASM_NUMBER=139
ASM_NUMFLOAT=140
ASM_BINFLOAT=141
ASM_DECFLOAT=142
ASM_HEXFLOAT=143
ASM_NUMINT=144
ASM_BININTEGER=145
ASM_DECINTEGER=146
ASM_HEXINTEGER=147
ASM_CHAR=148
ASM_MULTI_REL=149
ASM_MULTI_NAME=150
ASM_NAME=151
ASM_WS=152
ASM_COMMENT_LINE=153
ASM_COMMENT_BLOCK=154
IMPORT_SYSTEMFILE=155
IMPORT_LOCALFILE=156
IMPORT_WS=157
IMPORT_COMMENT_LINE=158
IMPORT_COMMENT_BLOCK=159
PARAM_LIST=12
CONDITION=13
DOT=14
ARROW=15
PLUS=16
MINUS=17
ASTERISK=18
DIVIDE=19
MODULO=20
INC=21
DEC=22
AND=23
BIT_NOT=24
BIT_XOR=25
BIT_OR=26
SHIFT_LEFT=27
SHIFT_RIGHT=28
EQUAL=29
NOT_EQUAL=30
LESS_THAN=31
LESS_THAN_EQUAL=32
GREATER_THAN_EQUAL=33
GREATER_THAN=34
LOGIC_AND=35
LOGIC_OR=36
ASSIGN=37
ASSIGN_COMPOUND=38
TYPEDEF=39
RESERVE=40
PC=41
TARGET=42
LINK=43
CPU=44
CODESEG=45
DATASEG=46
ENCODING=47
CONST=48
EXTERN=49
EXPORT=50
ALIGN=51
INLINE=52
VOLATILE=53
STATIC=54
INTERRUPT=55
REGISTER=56
ADDRESS=57
ADDRESS_ZEROPAGE=58
ADDRESS_MAINMEM=59
FORM_SSA=60
FORM_MA=61
INTRINSIC=62
CALLING=63
CALLINGCONVENTION=64
VARMODEL=65
IF=66
ELSE=67
WHILE=68
DO=69
FOR=70
SWITCH=71
RETURN=72
BREAK=73
CONTINUE=74
ASM=75
DEFAULT=76
CASE=77
STRUCT=78
ENUM=79
SIZEOF=80
TYPEID=81
DEFINED=82
KICKASM=83
RESOURCE=84
USES=85
CLOBBERS=86
BYTES=87
CYCLES=88
LOGIC_NOT=89
SIGNEDNESS=90
SIMPLETYPE=91
BOOLEAN=92
KICKASM_BODY=93
IMPORT=94
INCLUDE=95
PRAGMA=96
DEFINE=97
DEFINE_CONTINUE=98
UNDEF=99
IFDEF=100
IFNDEF=101
IFIF=102
ELIF=103
IFELSE=104
ENDIF=105
NUMBER=106
NUMFLOAT=107
BINFLOAT=108
DECFLOAT=109
HEXFLOAT=110
NUMINT=111
BININTEGER=112
DECINTEGER=113
HEXINTEGER=114
NAME=115
STRING=116
CHAR=117
WS=118
COMMENT_LINE=119
COMMENT_BLOCK=120
ASM_BYTE=121
ASM_MNEMONIC=122
ASM_IMM=123
ASM_COLON=124
ASM_COMMA=125
ASM_PAR_BEGIN=126
ASM_PAR_END=127
ASM_BRACKET_BEGIN=128
ASM_BRACKET_END=129
ASM_DOT=130
ASM_SHIFT_LEFT=131
ASM_SHIFT_RIGHT=132
ASM_PLUS=133
ASM_MINUS=134
ASM_LESS_THAN=135
ASM_GREATER_THAN=136
ASM_MULTIPLY=137
ASM_DIVIDE=138
ASM_CURLY_BEGIN=139
ASM_CURLY_END=140
ASM_NUMBER=141
ASM_NUMFLOAT=142
ASM_BINFLOAT=143
ASM_DECFLOAT=144
ASM_HEXFLOAT=145
ASM_NUMINT=146
ASM_BININTEGER=147
ASM_DECINTEGER=148
ASM_HEXINTEGER=149
ASM_CHAR=150
ASM_MULTI_REL=151
ASM_MULTI_NAME=152
ASM_NAME=153
ASM_WS=154
ASM_COMMENT_LINE=155
ASM_COMMENT_BLOCK=156
IMPORT_SYSTEMFILE=157
IMPORT_LOCALFILE=158
IMPORT_WS=159
IMPORT_COMMENT_LINE=160
IMPORT_COMMENT_BLOCK=161
';'=8
'..'=11
'?'=12
'->'=14
'%'=19
'++'=20
'--'=21
'&'=22
'~'=23
'^'=24
'|'=25
'=='=28
'!='=29
'<='=31
'>='=32
'&&'=34
'||'=35
'='=36
'typedef'=38
'reserve'=39
'pc'=40
'target'=41
'link'=42
'cpu'=43
'code_seg'=44
'data_seg'=45
'encoding'=46
'const'=47
'extern'=48
'export'=49
'align'=50
'inline'=51
'volatile'=52
'static'=53
'interrupt'=54
'register'=55
'__address'=56
'__zp'=57
'__mem'=58
'__ssa'=59
'__ma'=60
'calling'=61
'var_model'=63
'if'=64
'else'=65
'while'=66
'do'=67
'for'=68
'switch'=69
'return'=70
'break'=71
'continue'=72
'asm'=73
'default'=74
'case'=75
'struct'=76
'enum'=77
'sizeof'=78
'typeid'=79
'defined'=80
'kickasm'=81
'resource'=82
'uses'=83
'clobbers'=84
'bytes'=85
'cycles'=86
'!'=87
'#import'=92
'#include'=93
'#pragma'=94
'#define'=95
'#undef'=97
'#ifdef'=98
'#ifndef'=99
'#if'=100
'#elif'=101
'#else'=102
'#endif'=103
'.byte'=119
'#'=121
'...'=12
'?'=13
'->'=15
'%'=20
'++'=21
'--'=22
'&'=23
'~'=24
'^'=25
'|'=26
'=='=29
'!='=30
'<='=32
'>='=33
'&&'=35
'||'=36
'='=37
'typedef'=39
'reserve'=40
'pc'=41
'target'=42
'link'=43
'cpu'=44
'code_seg'=45
'data_seg'=46
'encoding'=47
'const'=48
'extern'=49
'export'=50
'align'=51
'inline'=52
'volatile'=53
'static'=54
'interrupt'=55
'register'=56
'__address'=57
'__zp'=58
'__mem'=59
'__ssa'=60
'__ma'=61
'__intrinsic'=62
'calling'=63
'var_model'=65
'if'=66
'else'=67
'while'=68
'do'=69
'for'=70
'switch'=71
'return'=72
'break'=73
'continue'=74
'asm'=75
'default'=76
'case'=77
'struct'=78
'enum'=79
'sizeof'=80
'typeid'=81
'defined'=82
'kickasm'=83
'resource'=84
'uses'=85
'clobbers'=86
'bytes'=87
'cycles'=88
'!'=89
'#import'=94
'#include'=95
'#pragma'=96
'#define'=97
'#undef'=99
'#ifdef'=100
'#ifndef'=101
'#if'=102
'#elif'=103
'#else'=104
'#endif'=105
'.byte'=121
'#'=123

View File

@ -142,6 +142,7 @@ parameterListDecl
parameterDecl
: declType declPointer* NAME #parameterDeclType
| SIMPLETYPE #parameterDeclVoid
| PARAM_LIST #parameterDeclList
;
globalDirective
@ -171,6 +172,7 @@ directive
| EXTERN #directiveExtern
| EXPORT #directiveExport
| INLINE #directiveInline
| INTRINSIC #directiveIntrinsic
| INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt
| RESERVE PAR_BEGIN NUMBER ( COMMA NUMBER )* PAR_END #directiveReserveZp
| CALLINGCONVENTION #directiveCallingConvention

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -9,231 +9,235 @@ SEMICOLON=8
COLON=9
COMMA=10
RANGE=11
CONDITION=12
DOT=13
ARROW=14
PLUS=15
MINUS=16
ASTERISK=17
DIVIDE=18
MODULO=19
INC=20
DEC=21
AND=22
BIT_NOT=23
BIT_XOR=24
BIT_OR=25
SHIFT_LEFT=26
SHIFT_RIGHT=27
EQUAL=28
NOT_EQUAL=29
LESS_THAN=30
LESS_THAN_EQUAL=31
GREATER_THAN_EQUAL=32
GREATER_THAN=33
LOGIC_AND=34
LOGIC_OR=35
ASSIGN=36
ASSIGN_COMPOUND=37
TYPEDEF=38
RESERVE=39
PC=40
TARGET=41
LINK=42
CPU=43
CODESEG=44
DATASEG=45
ENCODING=46
CONST=47
EXTERN=48
EXPORT=49
ALIGN=50
INLINE=51
VOLATILE=52
STATIC=53
INTERRUPT=54
REGISTER=55
ADDRESS=56
ADDRESS_ZEROPAGE=57
ADDRESS_MAINMEM=58
FORM_SSA=59
FORM_MA=60
CALLING=61
CALLINGCONVENTION=62
VARMODEL=63
IF=64
ELSE=65
WHILE=66
DO=67
FOR=68
SWITCH=69
RETURN=70
BREAK=71
CONTINUE=72
ASM=73
DEFAULT=74
CASE=75
STRUCT=76
ENUM=77
SIZEOF=78
TYPEID=79
DEFINED=80
KICKASM=81
RESOURCE=82
USES=83
CLOBBERS=84
BYTES=85
CYCLES=86
LOGIC_NOT=87
SIGNEDNESS=88
SIMPLETYPE=89
BOOLEAN=90
KICKASM_BODY=91
IMPORT=92
INCLUDE=93
PRAGMA=94
DEFINE=95
DEFINE_CONTINUE=96
UNDEF=97
IFDEF=98
IFNDEF=99
IFIF=100
ELIF=101
IFELSE=102
ENDIF=103
NUMBER=104
NUMFLOAT=105
BINFLOAT=106
DECFLOAT=107
HEXFLOAT=108
NUMINT=109
BININTEGER=110
DECINTEGER=111
HEXINTEGER=112
NAME=113
STRING=114
CHAR=115
WS=116
COMMENT_LINE=117
COMMENT_BLOCK=118
ASM_BYTE=119
ASM_MNEMONIC=120
ASM_IMM=121
ASM_COLON=122
ASM_COMMA=123
ASM_PAR_BEGIN=124
ASM_PAR_END=125
ASM_BRACKET_BEGIN=126
ASM_BRACKET_END=127
ASM_DOT=128
ASM_SHIFT_LEFT=129
ASM_SHIFT_RIGHT=130
ASM_PLUS=131
ASM_MINUS=132
ASM_LESS_THAN=133
ASM_GREATER_THAN=134
ASM_MULTIPLY=135
ASM_DIVIDE=136
ASM_CURLY_BEGIN=137
ASM_CURLY_END=138
ASM_NUMBER=139
ASM_NUMFLOAT=140
ASM_BINFLOAT=141
ASM_DECFLOAT=142
ASM_HEXFLOAT=143
ASM_NUMINT=144
ASM_BININTEGER=145
ASM_DECINTEGER=146
ASM_HEXINTEGER=147
ASM_CHAR=148
ASM_MULTI_REL=149
ASM_MULTI_NAME=150
ASM_NAME=151
ASM_WS=152
ASM_COMMENT_LINE=153
ASM_COMMENT_BLOCK=154
IMPORT_SYSTEMFILE=155
IMPORT_LOCALFILE=156
IMPORT_WS=157
IMPORT_COMMENT_LINE=158
IMPORT_COMMENT_BLOCK=159
PARAM_LIST=12
CONDITION=13
DOT=14
ARROW=15
PLUS=16
MINUS=17
ASTERISK=18
DIVIDE=19
MODULO=20
INC=21
DEC=22
AND=23
BIT_NOT=24
BIT_XOR=25
BIT_OR=26
SHIFT_LEFT=27
SHIFT_RIGHT=28
EQUAL=29
NOT_EQUAL=30
LESS_THAN=31
LESS_THAN_EQUAL=32
GREATER_THAN_EQUAL=33
GREATER_THAN=34
LOGIC_AND=35
LOGIC_OR=36
ASSIGN=37
ASSIGN_COMPOUND=38
TYPEDEF=39
RESERVE=40
PC=41
TARGET=42
LINK=43
CPU=44
CODESEG=45
DATASEG=46
ENCODING=47
CONST=48
EXTERN=49
EXPORT=50
ALIGN=51
INLINE=52
VOLATILE=53
STATIC=54
INTERRUPT=55
REGISTER=56
ADDRESS=57
ADDRESS_ZEROPAGE=58
ADDRESS_MAINMEM=59
FORM_SSA=60
FORM_MA=61
INTRINSIC=62
CALLING=63
CALLINGCONVENTION=64
VARMODEL=65
IF=66
ELSE=67
WHILE=68
DO=69
FOR=70
SWITCH=71
RETURN=72
BREAK=73
CONTINUE=74
ASM=75
DEFAULT=76
CASE=77
STRUCT=78
ENUM=79
SIZEOF=80
TYPEID=81
DEFINED=82
KICKASM=83
RESOURCE=84
USES=85
CLOBBERS=86
BYTES=87
CYCLES=88
LOGIC_NOT=89
SIGNEDNESS=90
SIMPLETYPE=91
BOOLEAN=92
KICKASM_BODY=93
IMPORT=94
INCLUDE=95
PRAGMA=96
DEFINE=97
DEFINE_CONTINUE=98
UNDEF=99
IFDEF=100
IFNDEF=101
IFIF=102
ELIF=103
IFELSE=104
ENDIF=105
NUMBER=106
NUMFLOAT=107
BINFLOAT=108
DECFLOAT=109
HEXFLOAT=110
NUMINT=111
BININTEGER=112
DECINTEGER=113
HEXINTEGER=114
NAME=115
STRING=116
CHAR=117
WS=118
COMMENT_LINE=119
COMMENT_BLOCK=120
ASM_BYTE=121
ASM_MNEMONIC=122
ASM_IMM=123
ASM_COLON=124
ASM_COMMA=125
ASM_PAR_BEGIN=126
ASM_PAR_END=127
ASM_BRACKET_BEGIN=128
ASM_BRACKET_END=129
ASM_DOT=130
ASM_SHIFT_LEFT=131
ASM_SHIFT_RIGHT=132
ASM_PLUS=133
ASM_MINUS=134
ASM_LESS_THAN=135
ASM_GREATER_THAN=136
ASM_MULTIPLY=137
ASM_DIVIDE=138
ASM_CURLY_BEGIN=139
ASM_CURLY_END=140
ASM_NUMBER=141
ASM_NUMFLOAT=142
ASM_BINFLOAT=143
ASM_DECFLOAT=144
ASM_HEXFLOAT=145
ASM_NUMINT=146
ASM_BININTEGER=147
ASM_DECINTEGER=148
ASM_HEXINTEGER=149
ASM_CHAR=150
ASM_MULTI_REL=151
ASM_MULTI_NAME=152
ASM_NAME=153
ASM_WS=154
ASM_COMMENT_LINE=155
ASM_COMMENT_BLOCK=156
IMPORT_SYSTEMFILE=157
IMPORT_LOCALFILE=158
IMPORT_WS=159
IMPORT_COMMENT_LINE=160
IMPORT_COMMENT_BLOCK=161
';'=8
'..'=11
'?'=12
'->'=14
'%'=19
'++'=20
'--'=21
'&'=22
'~'=23
'^'=24
'|'=25
'=='=28
'!='=29
'<='=31
'>='=32
'&&'=34
'||'=35
'='=36
'typedef'=38
'reserve'=39
'pc'=40
'target'=41
'link'=42
'cpu'=43
'code_seg'=44
'data_seg'=45
'encoding'=46
'const'=47
'extern'=48
'export'=49
'align'=50
'inline'=51
'volatile'=52
'static'=53
'interrupt'=54
'register'=55
'__address'=56
'__zp'=57
'__mem'=58
'__ssa'=59
'__ma'=60
'calling'=61
'var_model'=63
'if'=64
'else'=65
'while'=66
'do'=67
'for'=68
'switch'=69
'return'=70
'break'=71
'continue'=72
'asm'=73
'default'=74
'case'=75
'struct'=76
'enum'=77
'sizeof'=78
'typeid'=79
'defined'=80
'kickasm'=81
'resource'=82
'uses'=83
'clobbers'=84
'bytes'=85
'cycles'=86
'!'=87
'#import'=92
'#include'=93
'#pragma'=94
'#define'=95
'#undef'=97
'#ifdef'=98
'#ifndef'=99
'#if'=100
'#elif'=101
'#else'=102
'#endif'=103
'.byte'=119
'#'=121
'...'=12
'?'=13
'->'=15
'%'=20
'++'=21
'--'=22
'&'=23
'~'=24
'^'=25
'|'=26
'=='=29
'!='=30
'<='=32
'>='=33
'&&'=35
'||'=36
'='=37
'typedef'=39
'reserve'=40
'pc'=41
'target'=42
'link'=43
'cpu'=44
'code_seg'=45
'data_seg'=46
'encoding'=47
'const'=48
'extern'=49
'export'=50
'align'=51
'inline'=52
'volatile'=53
'static'=54
'interrupt'=55
'register'=56
'__address'=57
'__zp'=58
'__mem'=59
'__ssa'=60
'__ma'=61
'__intrinsic'=62
'calling'=63
'var_model'=65
'if'=66
'else'=67
'while'=68
'do'=69
'for'=70
'switch'=71
'return'=72
'break'=73
'continue'=74
'asm'=75
'default'=76
'case'=77
'struct'=78
'enum'=79
'sizeof'=80
'typeid'=81
'defined'=82
'kickasm'=83
'resource'=84
'uses'=85
'clobbers'=86
'bytes'=87
'cycles'=88
'!'=89
'#import'=94
'#include'=95
'#pragma'=96
'#define'=97
'#undef'=99
'#ifdef'=100
'#ifndef'=101
'#if'=102
'#elif'=103
'#else'=104
'#endif'=105
'.byte'=121
'#'=123

View File

@ -505,6 +505,18 @@ public class KickCParserBaseListener implements KickCParserListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterParameterDeclList(KickCParser.ParameterDeclListContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitParameterDeclList(KickCParser.ParameterDeclListContext ctx) { }
/**
* {@inheritDoc}
*
@ -781,6 +793,18 @@ public class KickCParserBaseListener implements KickCParserListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitDirectiveInline(KickCParser.DirectiveInlineContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) { }
/**
* {@inheritDoc}
*

View File

@ -300,6 +300,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitParameterDeclList(KickCParser.ParameterDeclListContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
@ -461,6 +468,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDirectiveInline(KickCParser.DirectiveInlineContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*

View File

@ -459,6 +459,18 @@ public interface KickCParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx);
/**
* Enter a parse tree produced by the {@code parameterDeclList}
* labeled alternative in {@link KickCParser#parameterDecl}.
* @param ctx the parse tree
*/
void enterParameterDeclList(KickCParser.ParameterDeclListContext ctx);
/**
* Exit a parse tree produced by the {@code parameterDeclList}
* labeled alternative in {@link KickCParser#parameterDecl}.
* @param ctx the parse tree
*/
void exitParameterDeclList(KickCParser.ParameterDeclListContext ctx);
/**
* Enter a parse tree produced by the {@code globalDirectiveReserve}
* labeled alternative in {@link KickCParser#globalDirective}.
@ -735,6 +747,18 @@ public interface KickCParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitDirectiveInline(KickCParser.DirectiveInlineContext ctx);
/**
* Enter a parse tree produced by the {@code directiveIntrinsic}
* labeled alternative in {@link KickCParser#directive}.
* @param ctx the parse tree
*/
void enterDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx);
/**
* Exit a parse tree produced by the {@code directiveIntrinsic}
* labeled alternative in {@link KickCParser#directive}.
* @param ctx the parse tree
*/
void exitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx);
/**
* Enter a parse tree produced by the {@code directiveInterrupt}
* labeled alternative in {@link KickCParser#directive}.

View File

@ -278,6 +278,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx);
/**
* Visit a parse tree produced by the {@code parameterDeclList}
* labeled alternative in {@link KickCParser#parameterDecl}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitParameterDeclList(KickCParser.ParameterDeclListContext ctx);
/**
* Visit a parse tree produced by the {@code globalDirectiveReserve}
* labeled alternative in {@link KickCParser#globalDirective}.
@ -439,6 +446,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitDirectiveInline(KickCParser.DirectiveInlineContext ctx);
/**
* Visit a parse tree produced by the {@code directiveIntrinsic}
* labeled alternative in {@link KickCParser#directive}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx);
/**
* Visit a parse tree produced by the {@code directiveInterrupt}
* labeled alternative in {@link KickCParser#directive}.

View File

@ -252,10 +252,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
// Check that the declaration matches any existing declaration!
final Symbol existingSymbol = program.getScope().getSymbol(procedure.getRef());
if(existingSymbol!=null) {
if(existingSymbol != null) {
// Already declared - check equality
if(!(existingSymbol instanceof Procedure) || !SymbolTypeConversion.procedureDeclarationMatch((Procedure) existingSymbol, procedure))
throw new CompileError("Error! Conflicting declarations for: "+procedure.getFullName(), new StatementSource(ctx));
throw new CompileError("Error! Conflicting declarations for: " + procedure.getFullName(), new StatementSource(ctx));
} else {
// Not declared before - add it
program.getScope().add(procedure);
@ -263,7 +263,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
if(ctx.declFunctionBody() != null) {
// Make sure directives and more are taken from the procedure with the body!
if(existingSymbol!=null) {
if(existingSymbol != null) {
program.getScope().remove(existingSymbol);
program.getScope().add(procedure);
}
@ -271,7 +271,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
// Check that the body has not already been added
for(Statement statement : sequence.getStatements())
if(statement instanceof StatementProcedureBegin && ((StatementProcedureBegin) statement).getProcedure().equals(procedure.getRef()))
throw new CompileError("Error! Redefinition of function: "+procedure.getFullName(), StatementSource.procedureBegin(ctx));
throw new CompileError("Error! Redefinition of function: " + procedure.getFullName(), StatementSource.procedureBegin(ctx));
// Add the body
scopeStack.push(procedure);
sequence.addStatement(new StatementProcedureBegin(procedure.getRef(), StatementSource.procedureBegin(ctx), Comment.NO_COMMENTS));
@ -302,11 +302,14 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return null;
}
@Override
public List<Variable> visitParameterListDecl(KickCParser.ParameterListDeclContext ctx) {
ArrayList<Variable> parameterDecls = new ArrayList<>();
boolean encounteredVariableLengthParamList = false;
for(KickCParser.ParameterDeclContext parameterDeclCtx : ctx.parameterDecl()) {
if(encounteredVariableLengthParamList) {
throw new CompileError("Variable length parameter list is only legal as the last parameter.", new StatementSource(ctx));
}
Object parameterDecl = this.visit(parameterDeclCtx);
if(parameterDecl.equals(SymbolType.VOID)) {
if(ctx.parameterDecl().size() == 1) {
@ -315,6 +318,11 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
} else {
throw new CompileError("Illegal void parameter.", new StatementSource(ctx));
}
} else if(parameterDecl == PARAM_LIST) {
// A "..." parameter list. Update the procedure.
final Procedure procedure = (Procedure) getCurrentScope();
procedure.setVariableLengthParameterList(true);
encounteredVariableLengthParamList = true;
} else if(parameterDecl instanceof Variable) {
parameterDecls.add((Variable) parameterDecl);
} else {
@ -345,6 +353,14 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return SymbolType.VOID;
}
/** Singleton signalling a "..." parameter list. */
public static Object PARAM_LIST = new Object();
@Override
public Object visitParameterDeclList(KickCParser.ParameterDeclListContext ctx) {
return PARAM_LIST;
}
@Override
public Object visitDeclKasm(KickCParser.DeclKasmContext ctx) {
String kasm = ctx.KICKASM_BODY().getText();
@ -528,7 +544,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
resourceName = resourceName.substring(1, resourceName.length() - 1);
Path currentPath = cParser.getSourceFolderPath(ctx);
File resourceFile = SourceLoader.loadFile(resourceName, currentPath, new ArrayList<>());
if(resourceFile==null)
if(resourceFile == null)
throw new CompileError("File not found " + resourceName);
program.addAsmResourceFile(resourceFile.toPath());
if(program.getLog().isVerboseParse()) {
@ -999,6 +1015,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
procedure.setInterruptType(((Directive.Interrupt) directive).interruptType);
} else if(directive instanceof Directive.ReserveZp) {
procedure.setReservedZps(((Directive.ReserveZp) directive).reservedZp);
} else if(directive instanceof Directive.Intrinsic) {
procedure.setDeclaredIntrinsic(true);
} else {
throw new CompileError("Unsupported function directive " + directive, source);
}
@ -1034,6 +1052,11 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return new Directive.Inline();
}
@Override
public Object visitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) {
return new Directive.Intrinsic();
}
@Override
public Object visitDirectiveInterrupt(KickCParser.DirectiveInterruptContext ctx) {
String interruptType;
@ -1289,6 +1312,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
/**
* Add code to evaluate a comma-expr condition (used in while/for/...).
*
* @param conditionCtx The comma-expr condition to evaluate
* @param statementSource The statement source used for errors
* @return The RValue of the condition
@ -1679,7 +1703,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
RValue rValue;
if(exprCtx != null) {
if(SymbolType.VOID.equals(procedure.getReturnType())) {
throw new CompileError("Error! Return value from void function "+procedure.getFullName(), new StatementSource(ctx));
throw new CompileError("Error! Return value from void function " + procedure.getFullName(), new StatementSource(ctx));
}
PrePostModifierHandler.addPreModifiers(this, exprCtx, new StatementSource(ctx));
rValue = (RValue) this.visit(exprCtx);

View File

@ -8,7 +8,7 @@ import dk.camelot64.kickc.model.symbols.Procedure;
import java.util.Collection;
/** Pass that checks that all functions declared have a definition with a body*/
/** Pass that checks that all functions declared have a definition with a body */
public class Pass1AssertProcedureDefined extends Pass1Base {
public Pass1AssertProcedureDefined(Program program) {
@ -19,6 +19,11 @@ public class Pass1AssertProcedureDefined extends Pass1Base {
public boolean step() {
final Collection<Procedure> allProcedures = getScope().getAllProcedures(true);
for(Procedure procedure : allProcedures) {
if(procedure.isDeclaredIntrinsic()) {
if(!Procedure.INTRINSIC_PROCEDURES.contains(procedure.getLocalName()))
throw new CompileError("Error! Undefined intrinsic function: " + procedure.getFullName());
continue;
}
final Label procedureLabel = procedure.getLabel();
final ControlFlowBlock procedureBlock = getGraph().getBlock(procedureLabel.getRef());
if(procedureBlock == null)

View File

@ -0,0 +1,121 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.Comment;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.*;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Rewrite printf() calls to a series of printf-calls by parsing the format string.
*/
public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
/** The printf procedure name. */
public static final String INTRINSIC_PRINTF_NAME = "printf";
public Pass1PrintfIntrinsicRewrite(Program program) {
super(program);
}
@Override
public boolean step() {
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
final ListIterator<Statement> stmtIt = block.getStatements().listIterator();
while(stmtIt.hasNext()) {
Statement statement = stmtIt.next();
if(statement instanceof StatementCall && ((StatementCall) statement).getProcedureName().equals(INTRINSIC_PRINTF_NAME)) {
StatementCall printfCall = (StatementCall) statement;
final List<RValue> parameters = printfCall.getParameters();
final RValue formatParameter = parameters.get(0);
if(!(formatParameter instanceof ConstantValue))
throw new CompileError("Error! Only constant printf() format parameter supported!", statement);
final ConstantLiteral formatLiteral = ((ConstantValue) formatParameter).calculateLiteral(getProgram().getScope());
if(!(formatLiteral instanceof ConstantString))
throw new CompileError("Error! printf() format parameter must be a string!", statement);
final String formatString = ((ConstantString) formatLiteral).getString();
final StringEncoding formatEncoding = ((ConstantString) formatLiteral).getEncoding();
// Remove the call to printf()
stmtIt.remove();
// Printf Placeholder Format String
// "%" start
// ([1-9][0-9]* "$")? parameter (gives the # of the parameter to use)
// [-+ 0'#]* flags (different flags affecting the formatting "-": left-align, "0": zero-prepend, "+": always sign)
// [1-9][0-9]* width (the minimum number of characters)
// ("hh" | "l" )? length (specifies the type of integer "hh": char "": int, "l": long)
// [%diuxXoscp] type (specifies the type of the parameter/output "d"/"i" decimal signed, "u": decimal unsigned, "x": hexadecimal unsigned (lowercase), "X": hexadecimal unsigned (uppercase), "o": octal unsigned, "s": string, "c": character, "p": pointer, "%": output "%" )
Pattern pattern = Pattern.compile("%([1-9][0-9]*[$])?([-+0#]*)([1-9][0-9]*)?(hh|l)?([%diuxXoscp])");
final Matcher matcher = pattern.matcher(formatString);
int formatIdx = 0;
int paramIdx = 1;
while(true) {
// Find the next pattern match!
boolean found = matcher.find();
if(!found) {
// No more matching patterns
break;
}
final int start = matcher.start();
final int end = matcher.end();
final String param = matcher.group(1);
final String flags = matcher.group(2);
final String width = matcher.group(3);
final String length = matcher.group(4);
final String type = matcher.group(5);
if(param!=null)
throw new CompileError("printf parameter field not supported", printfCall);
// First grab the non-matching part
String prefix = formatString.substring(formatIdx, start);
printfConstantString(prefix, printfCall, stmtIt, formatEncoding);
formatIdx = end;
if(type.equals("s")) {
// A string
long w = (width==null)?0:Integer.parseInt(width);
long leftJustify = (flags!=null && flags.contains("-"))?1:0;
final ValueList format_string_struct = new ValueList(Arrays.asList(new ConstantInteger(w, SymbolType.BYTE), new ConstantInteger(leftJustify, SymbolType.BYTE)));
final StatementCall call_printf_str = new StatementCall(null, "printf_string", Arrays.asList(parameters.get(paramIdx), format_string_struct), printfCall.getSource(), Comment.NO_COMMENTS);
call_printf_str.setProcedure(getScope().getLocalProcedure(call_printf_str.getProcedureName()).getRef());
stmtIt.add(call_printf_str);
paramIdx++;
} else if(type.equals("d")) {
System.out.println("decimal");
}
}
// Grab the rest
String suffix = formatString.substring(formatIdx);
printfConstantString(suffix, printfCall, stmtIt, formatEncoding);
}
}
}
return false;
}
/**
* Add a printf_str() that prints a constant string.
* @param prefix The string to print
* @param printfCall The original printf call
* @param stmtIt The statement iterator to add to
* @param encoding The string encoding
*/
private void printfConstantString(String prefix, StatementCall printfCall, ListIterator<Statement> stmtIt, StringEncoding encoding) {
final StatementCall call_printf_str = new StatementCall(null, "printf_str", Arrays.asList(new ConstantString(prefix, encoding, true)), printfCall.getSource(), Comment.NO_COMMENTS);
call_printf_str.setProcedure(getScope().getLocalProcedure(call_printf_str.getProcedureName()).getRef());
stmtIt.add(call_printf_str);
}
}

View File

@ -6,7 +6,6 @@ import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Scope;
/**
* Updates procedure calls to point to the actual procedure called.
@ -29,11 +28,12 @@ public class Pass1Procedures extends Pass2SsaOptimization {
throw new CompileError("Called procedure not found. " + call.toString(getProgram(), false), statement.getSource());
}
call.setProcedure(procedure.getRef());
if(procedure.getParameters().size() != call.getParameters().size()) {
if(procedure.isVariableLengthParameterList() && procedure.getParameters().size() > call.getParameters().size()) {
throw new CompileError("Wrong number of parameters in call. Expected " + procedure.getParameters().size() + " or more. " + statement.toString(), statement.getSource());
} else if(!procedure.isVariableLengthParameterList() && procedure.getParameters().size() != call.getParameters().size()) {
throw new CompileError("Wrong number of parameters in call. Expected " + procedure.getParameters().size() + ". " + statement.toString(), statement.getSource());
}
}
}
}
return false;

View File

@ -40,6 +40,11 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testPintf10() throws IOException, URISyntaxException {
compileAndCompare("printf-10.c", log());
}
@Test
public void testProblemNegateConst() throws IOException, URISyntaxException {
compileAndCompare("problem-negate-const.c");
@ -3896,6 +3901,16 @@ public class TestPrograms {
assertError("tofewparams.c", "Wrong number of parameters in call");
}
@Test
public void testToFewParamsVarlength() throws IOException, URISyntaxException {
assertError("tofewparams-varlength.c", "Wrong number of parameters in call");
}
@Test
public void testVarlengthError() throws IOException, URISyntaxException {
assertError("varlength-error.c", "Variable length parameter list is only legal as the last parameter.");
}
@Test
public void testNoReturn() throws IOException, URISyntaxException {
assertError("noreturn.c", "Method must end with a return statement", false);

View File

@ -0,0 +1,13 @@
{
"env": {
"myDefaultIncludePath": ["${workspaceFolder}", "~/c64/kickc_local/include"]
},
"configurations": [
{
"name": "Mac",
"includePath": ["${myDefaultIncludePath}", "~/c64/kickc_local/include"],
"defines": ["FOO", "BAR=100"]
}
],
"version": 4
}

146
src/test/kc/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,146 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "KickAssembler",
"type": "shell",
"command": "java",
"args": [
"-jar",
"${config:kickassembler.kickAssPath}",
"${file}",
"-odir",
"build",
"-showmem",
"-execute",
"${workspaceFolder}\\tools\\exomize.bat"
],
"group": "build",
"problemMatcher": []
},
{
"label": "KickAsm Vice",
"type": "shell",
"command": "java",
"args": [
"-jar",
"${config:kickassembler.kickAssPath}",
"${file}",
"-define",
"AUTORUN",
"-showmem",
"-vicesymbols",
"-execute",
"\"${config:vice.vicePath}\" -moncommands ${fileBasenameNoExtension}.vs"
],
"group": "build"
},
{
"label": "KickAsm Vice Debug",
"type": "shell",
"command": "java",
"args": [
"-jar",
"${config:kickassembler.kickAssPath}",
"${file}",
"-odir",
"debug",
"-define",
"AUTORUN",
"-define",
"DEBUG",
"-showmem",
"-vicesymbols",
":debug=true",
"-execute",
"\"${config:vice.vicePath}\" -moncommands ${fileBasenameNoExtension}.vs"
],
"group": "build"
},
{
"label": "KickAsm C64Debugger",
"type": "shell",
"command": "java",
"args": [
"-jar",
"${config:kickassembler.kickAssPath}",
"${file}",
"-odir",
"bin",
"-define",
"AUTORUN",
"-showmem",
"-debugdump",
"-execute",
"\"${config:c64debugger.c64debuggerPath}\""
],
"group": "build"
},
{
"label": "KickAsm C64Debugger Debug",
"type": "shell",
"command": "java",
"args": [
"-jar",
"${config:kickassembler.kickAssPath}",
"${file}",
"-odir",
"debug",
"-define",
"AUTORUN",
"-define",
"DEBUG",
"-showmem",
"-debugdump",
":debug=true",
"-execute",
"\"${config:c64debugger.c64debuggerPath}\""
],
"group": "build"
},
{
"label": "KickAsm Build",
"command": "java",
"args": [
"-jar",
"${config:kickassembler.kickAssPath}",
"${file}",
"-odir",
"build",
"-showmem"
],
"group": "build"
},
{
"label": "KickC Build & Run",
"type": "shell",
"cwd": "${workspaceFolder}",
"command": "~/c64/kickc_local/bin/kickc.sh",
"args": [
"-odir",
"~/c64/tmp/",
"-e",
"${relativeFile}"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
},
{
"label": "Exomize Build",
"command": "${workspaceFolder}\\tools\\exomize.bat",
"args": [
"${config:exomizer.exomizerPath}",
"${file}"
],
"dependsOn": [
"KickAsm Build"
],
"group": "build"
}
]
}

33
src/test/kc/printf-10.c Normal file
View File

@ -0,0 +1,33 @@
// Tests printf function call rewriting
// A simple string - with the printf-sub cuntions in the same file.
__intrinsic void printf(char* format, ...);
char * screen = 0x0400;
char idx = 0;
void printf_str(char* str) {
while(*str) {
*screen++ = *str++;
}
}
// Format specifying how to format a printed string
struct printf_format_string {
// The minimal number of chars to output (used for padding with spaces or 0).
char min_length;
// Justify left instead of right, which is the default.
char justify_left;
};
// Print a string value using a specific format
// Handles justification and min length
void printf_string(char* str, struct printf_format_string format) {
printf_str(str);
}
void main() {
char name[] = "Jesper";
printf("Hello, I am %s. who are you?", name);
}

View File

@ -0,0 +1,7 @@
// To few parameters to a function with variable parameter list length
__intrinsic void printf(char* format, ...);
void main() {
printf();
}

View File

@ -0,0 +1,7 @@
// A procedure with the varlength in the middle of the list
void printf(char* format, ..., int x);
void main() {
printf("c", 1, 2, 3);
}

View File

@ -0,0 +1,73 @@
// Tests printf function call rewriting
// A simple string - with the printf-sub cuntions in the same file.
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label screen = 2
main: {
// printf("Hello, I am %s. who are you?", name)
lda #<$400
sta.z screen
lda #>$400
sta.z screen+1
lda #<str
sta.z printf_str.str
lda #>str
sta.z printf_str.str+1
jsr printf_str
// printf("Hello, I am %s. who are you?", name)
jsr printf_string
// printf("Hello, I am %s. who are you?", name)
lda #<str1
sta.z printf_str.str
lda #>str1
sta.z printf_str.str+1
jsr printf_str
// }
rts
name: .text "Jesper"
.byte 0
str: .text "Hello, I am "
.byte 0
str1: .text ". who are you?"
.byte 0
}
// printf_str(byte* zp(4) str)
printf_str: {
.label str = 4
__b1:
// while(*str)
ldy #0
lda (str),y
cmp #0
bne __b2
// }
rts
__b2:
// *screen++ = *str++
ldy #0
lda (str),y
sta (screen),y
// *screen++ = *str++;
inc.z screen
bne !+
inc.z screen+1
!:
inc.z str
bne !+
inc.z str+1
!:
jmp __b1
}
// Print a string value using a specific format
// Handles justification and min length
printf_string: {
// printf_str(str)
lda #<main.name
sta.z printf_str.str
lda #>main.name
sta.z printf_str.str+1
jsr printf_str
// }
rts
}

View File

@ -0,0 +1,54 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] phi()
[5] call printf_str
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call printf_string
to:main::@2
main::@2: scope:[main] from main::@1
[8] phi()
[9] call printf_str
to:main::@return
main::@return: scope:[main] from main::@2
[10] return
to:@return
(void()) printf_str((byte*) printf_str::str)
printf_str: scope:[printf_str] from main main::@2 printf_string
[11] (byte*) screen#23 ← phi( main/(byte*) 1024 main::@2/(byte*) screen#10 printf_string/(byte*) screen#10 )
[11] (byte*) printf_str::str#6 ← phi( main/(const byte*) main::str main::@2/(const byte*) main::str1 printf_string/(const byte*) main::name )
to:printf_str::@1
printf_str::@1: scope:[printf_str] from printf_str printf_str::@2
[12] (byte*) screen#10 ← phi( printf_str/(byte*) screen#23 printf_str::@2/(byte*) screen#1 )
[12] (byte*) printf_str::str#4 ← phi( printf_str/(byte*) printf_str::str#6 printf_str::@2/(byte*) printf_str::str#0 )
[13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2
to:printf_str::@return
printf_str::@return: scope:[printf_str] from printf_str::@1
[14] return
to:@return
printf_str::@2: scope:[printf_str] from printf_str::@1
[15] *((byte*) screen#10) ← *((byte*) printf_str::str#4)
[16] (byte*) screen#1 ← ++ (byte*) screen#10
[17] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#4
to:printf_str::@1
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
printf_string: scope:[printf_string] from main::@1
[18] phi()
[19] call printf_str
to:printf_string::@return
printf_string::@return: scope:[printf_string] from printf_string
[20] return
to:@return

834
src/test/ref/printf-10.log Normal file
View File

@ -0,0 +1,834 @@
Added struct type cast to parameter value list call printf_string (const byte*) main::name (struct printf_format_string){ (byte) 0, (byte) 0 }
Created struct value member variable (byte) printf_string::format_min_length
Created struct value member variable (byte) printf_string::format_justify_left
Converted struct value to member variables (struct printf_format_string) printf_string::format
Converted procedure struct value parameter to member unwinding (void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
Converted call struct value parameter to member unwinding call printf_string (const byte*) main::name (byte) 0 (byte) 0
Warning! Adding boolean cast to non-boolean condition *((byte*) printf_str::str)
Identified constant variable (byte) idx
Eliminating unused variable with no statement (void~) main::$0
Culled Empty Block (label) printf_str::@4
Culled Empty Block (label) printf_str::@3
Culled Empty Block (label) printf_str::@5
Culled Empty Block (label) printf_str::@6
Culled Empty Block (label) @1
Culled Empty Block (label) @2
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) screen#0 ← (byte*)(number) $400
to:@3
(void()) printf_str((byte*) printf_str::str)
printf_str: scope:[printf_str] from main main::@2 printf_string
(byte*) screen#23 ← phi( main/(byte*) screen#21 main::@2/(byte*) screen#6 printf_string/(byte*) screen#20 )
(byte*) printf_str::str#6 ← phi( main/(byte*) printf_str::str#2 main::@2/(byte*) printf_str::str#3 printf_string/(byte*) printf_str::str#1 )
to:printf_str::@1
printf_str::@1: scope:[printf_str] from printf_str printf_str::@2
(byte*) screen#19 ← phi( printf_str/(byte*) screen#23 printf_str::@2/(byte*) screen#1 )
(byte*) printf_str::str#4 ← phi( printf_str/(byte*) printf_str::str#6 printf_str::@2/(byte*) printf_str::str#0 )
(bool~) printf_str::$0 ← (number) 0 != *((byte*) printf_str::str#4)
if((bool~) printf_str::$0) goto printf_str::@2
to:printf_str::@return
printf_str::@2: scope:[printf_str] from printf_str::@1
(byte*) screen#10 ← phi( printf_str::@1/(byte*) screen#19 )
(byte*) printf_str::str#5 ← phi( printf_str::@1/(byte*) printf_str::str#4 )
*((byte*) screen#10) ← *((byte*) printf_str::str#5)
(byte*) screen#1 ← ++ (byte*) screen#10
(byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#5
to:printf_str::@1
printf_str::@return: scope:[printf_str] from printf_str::@1
(byte*) screen#11 ← phi( printf_str::@1/(byte*) screen#19 )
(byte*) screen#2 ← (byte*) screen#11
return
to:@return
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
printf_string: scope:[printf_string] from main::@1
(byte*) screen#20 ← phi( main::@1/(byte*) screen#5 )
(byte*) printf_string::str#1 ← phi( main::@1/(byte*) printf_string::str#0 )
(byte*) printf_str::str#1 ← (byte*) printf_string::str#1
call printf_str
to:printf_string::@1
printf_string::@1: scope:[printf_string] from printf_string
(byte*) screen#12 ← phi( printf_string/(byte*) screen#2 )
(byte*) screen#3 ← (byte*) screen#12
to:printf_string::@return
printf_string::@return: scope:[printf_string] from printf_string::@1
(byte*) screen#13 ← phi( printf_string::@1/(byte*) screen#3 )
(byte*) screen#4 ← (byte*) screen#13
return
to:@return
(void()) main()
main: scope:[main] from @3
(byte*) screen#21 ← phi( @3/(byte*) screen#22 )
(byte*) printf_str::str#2 ← (const byte*) main::str
call printf_str
to:main::@1
main::@1: scope:[main] from main
(byte*) screen#14 ← phi( main/(byte*) screen#2 )
(byte*) screen#5 ← (byte*) screen#14
(byte*) printf_string::str#0 ← (const byte*) main::name
(byte) printf_string::format_min_length#0 ← (byte) 0
(byte) printf_string::format_justify_left#0 ← (byte) 0
call printf_string
to:main::@2
main::@2: scope:[main] from main::@1
(byte*) screen#15 ← phi( main::@1/(byte*) screen#4 )
(byte*) screen#6 ← (byte*) screen#15
(byte*) printf_str::str#3 ← (const byte*) main::str1
call printf_str
to:main::@3
main::@3: scope:[main] from main::@2
(byte*) screen#16 ← phi( main::@2/(byte*) screen#2 )
(byte*) screen#7 ← (byte*) screen#16
to:main::@return
main::@return: scope:[main] from main::@3
(byte*) screen#17 ← phi( main::@3/(byte*) screen#7 )
(byte*) screen#8 ← (byte*) screen#17
return
to:@return
@3: scope:[] from @begin
(byte*) screen#22 ← phi( @begin/(byte*) screen#0 )
call main
to:@4
@4: scope:[] from @3
(byte*) screen#18 ← phi( @3/(byte*) screen#8 )
(byte*) screen#9 ← (byte*) screen#18
to:@end
@end: scope:[] from @4
SYMBOL TABLE SSA
(label) @3
(label) @4
(label) @begin
(label) @end
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(const byte*) main::name[] = (byte*) "Jesper"
(const byte*) main::str[(byte) $d] = (byte*) "Hello, I am "
(const byte*) main::str1[(byte) $f] = (byte*) ". who are you?"
(byte) printf_format_string::justify_left
(byte) printf_format_string::min_length
(void()) printf_str((byte*) printf_str::str)
(bool~) printf_str::$0
(label) printf_str::@1
(label) printf_str::@2
(label) printf_str::@return
(byte*) printf_str::str
(byte*) printf_str::str#0
(byte*) printf_str::str#1
(byte*) printf_str::str#2
(byte*) printf_str::str#3
(byte*) printf_str::str#4
(byte*) printf_str::str#5
(byte*) printf_str::str#6
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
(label) printf_string::@1
(label) printf_string::@return
(struct printf_format_string) printf_string::format
(byte) printf_string::format_justify_left
(byte) printf_string::format_justify_left#0
(byte) printf_string::format_min_length
(byte) printf_string::format_min_length#0
(byte*) printf_string::str
(byte*) printf_string::str#0
(byte*) printf_string::str#1
(byte*) screen
(byte*) screen#0
(byte*) screen#1
(byte*) screen#10
(byte*) screen#11
(byte*) screen#12
(byte*) screen#13
(byte*) screen#14
(byte*) screen#15
(byte*) screen#16
(byte*) screen#17
(byte*) screen#18
(byte*) screen#19
(byte*) screen#2
(byte*) screen#20
(byte*) screen#21
(byte*) screen#22
(byte*) screen#23
(byte*) screen#3
(byte*) screen#4
(byte*) screen#5
(byte*) screen#6
(byte*) screen#7
(byte*) screen#8
(byte*) screen#9
Adding number conversion cast (unumber) 0 in (bool~) printf_str::$0 ← (number) 0 != *((byte*) printf_str::str#4)
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias printf_str::str#4 = printf_str::str#5
Alias screen#10 = screen#19 screen#11 screen#2
Alias screen#12 = screen#3 screen#13 screen#4
Alias screen#14 = screen#5
Alias screen#15 = screen#6
Alias screen#16 = screen#7 screen#17 screen#8
Alias screen#0 = screen#22
Alias screen#18 = screen#9
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte*) printf_string::str#1 (byte*) printf_string::str#0
Identical Phi Values (byte*) screen#20 (byte*) screen#14
Identical Phi Values (byte*) screen#12 (byte*) screen#10
Identical Phi Values (byte*) screen#21 (byte*) screen#0
Identical Phi Values (byte*) screen#14 (byte*) screen#10
Identical Phi Values (byte*) screen#15 (byte*) screen#12
Identical Phi Values (byte*) screen#16 (byte*) screen#10
Identical Phi Values (byte*) screen#18 (byte*) screen#16
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) printf_str::$0 [4] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte*) screen#0 = (byte*) 1024
Constant (const byte*) printf_str::str#2 = main::str
Constant (const byte*) printf_string::str#0 = main::name
Constant (const byte) printf_string::format_min_length#0 = 0
Constant (const byte) printf_string::format_justify_left#0 = 0
Constant (const byte*) printf_str::str#3 = main::str1
Successful SSA optimization Pass2ConstantIdentification
Constant (const byte*) printf_str::str#1 = printf_string::str#0
Successful SSA optimization Pass2ConstantIdentification
Eliminating unused constant (const byte) printf_string::format_min_length#0
Eliminating unused constant (const byte) printf_string::format_justify_left#0
Successful SSA optimization PassNEliminateUnusedVars
Inlining constant with var siblings (const byte*) printf_str::str#2
Inlining constant with var siblings (const byte*) printf_str::str#3
Inlining constant with var siblings (const byte*) printf_str::str#1
Inlining constant with var siblings (const byte*) screen#0
Constant inlined printf_string::str#0 = (const byte*) main::name
Constant inlined printf_str::str#2 = (const byte*) main::str
Constant inlined printf_str::str#1 = (const byte*) main::name
Constant inlined screen#0 = (byte*) 1024
Constant inlined printf_str::str#3 = (const byte*) main::str1
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @3
Adding NOP phi() at start of @4
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@1
Adding NOP phi() at start of main::@3
Adding NOP phi() at start of printf_string::@1
CALL GRAPH
Calls in [] to main:2
Calls in [main] to printf_str:6 printf_string:8 printf_str:10
Calls in [printf_string] to printf_str:25
Created 4 initial phi equivalence classes
Coalesced [9] screen#24 ← screen#10
Coalesced [14] printf_str::str#7 ← printf_str::str#6
Coalesced (already) [15] screen#26 ← screen#23
Coalesced [22] printf_str::str#8 ← printf_str::str#0
Coalesced [23] screen#27 ← screen#1
Coalesced (already) [24] screen#25 ← screen#10
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) @4
Culled Empty Block (label) main::@3
Culled Empty Block (label) printf_string::@1
Renumbering block @3 to @1
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@1
Adding NOP phi() at start of main::@2
Adding NOP phi() at start of printf_string
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] phi()
[5] call printf_str
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call printf_string
to:main::@2
main::@2: scope:[main] from main::@1
[8] phi()
[9] call printf_str
to:main::@return
main::@return: scope:[main] from main::@2
[10] return
to:@return
(void()) printf_str((byte*) printf_str::str)
printf_str: scope:[printf_str] from main main::@2 printf_string
[11] (byte*) screen#23 ← phi( main/(byte*) 1024 main::@2/(byte*) screen#10 printf_string/(byte*) screen#10 )
[11] (byte*) printf_str::str#6 ← phi( main/(const byte*) main::str main::@2/(const byte*) main::str1 printf_string/(const byte*) main::name )
to:printf_str::@1
printf_str::@1: scope:[printf_str] from printf_str printf_str::@2
[12] (byte*) screen#10 ← phi( printf_str/(byte*) screen#23 printf_str::@2/(byte*) screen#1 )
[12] (byte*) printf_str::str#4 ← phi( printf_str/(byte*) printf_str::str#6 printf_str::@2/(byte*) printf_str::str#0 )
[13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2
to:printf_str::@return
printf_str::@return: scope:[printf_str] from printf_str::@1
[14] return
to:@return
printf_str::@2: scope:[printf_str] from printf_str::@1
[15] *((byte*) screen#10) ← *((byte*) printf_str::str#4)
[16] (byte*) screen#1 ← ++ (byte*) screen#10
[17] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#4
to:printf_str::@1
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
printf_string: scope:[printf_string] from main::@1
[18] phi()
[19] call printf_str
to:printf_string::@return
printf_string::@return: scope:[printf_string] from printf_string
[20] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte) printf_format_string::justify_left
(byte) printf_format_string::min_length
(void()) printf_str((byte*) printf_str::str)
(byte*) printf_str::str
(byte*) printf_str::str#0 20002.0
(byte*) printf_str::str#4 10251.25
(byte*) printf_str::str#6 1001.0
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
(struct printf_format_string) printf_string::format
(byte) printf_string::format_justify_left
(byte) printf_string::format_min_length
(byte*) printf_string::str
(byte*) screen
(byte*) screen#1 10001.0
(byte*) screen#10 2828.7272727272725
(byte*) screen#23 1113.0
Initial phi equivalence classes
[ screen#23 screen#10 screen#1 ]
[ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
Complete equivalence classes
[ screen#23 screen#10 screen#1 ]
[ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
Allocated zp[2]:2 [ screen#23 screen#10 screen#1 ]
Allocated zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Tests printf function call rewriting
// A simple string - with the printf-sub cuntions in the same file.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label screen = 2
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [5] call printf_str
// [11] phi from main to printf_str [phi:main->printf_str]
printf_str_from_main:
// [11] phi (byte*) screen#23 = (byte*) 1024 [phi:main->printf_str#0] -- pbuz1=pbuc1
lda #<$400
sta.z screen
lda #>$400
sta.z screen+1
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str [phi:main->printf_str#1] -- pbuz1=pbuc1
lda #<str
sta.z printf_str.str
lda #>str
sta.z printf_str.str+1
jsr printf_str
// [6] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
jmp __b1
// main::@1
__b1:
// [7] call printf_string
// [18] phi from main::@1 to printf_string [phi:main::@1->printf_string]
printf_string_from___b1:
jsr printf_string
// [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
__b2_from___b1:
jmp __b2
// main::@2
__b2:
// [9] call printf_str
// [11] phi from main::@2 to printf_str [phi:main::@2->printf_str]
printf_str_from___b2:
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:main::@2->printf_str#0] -- register_copy
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str1 [phi:main::@2->printf_str#1] -- pbuz1=pbuc1
lda #<str1
sta.z printf_str.str
lda #>str1
sta.z printf_str.str+1
jsr printf_str
jmp __breturn
// main::@return
__breturn:
// [10] return
rts
name: .text "Jesper"
.byte 0
str: .text "Hello, I am "
.byte 0
str1: .text ". who are you?"
.byte 0
}
// printf_str
// printf_str(byte* zp(4) str)
printf_str: {
.label str = 4
// [12] phi from printf_str printf_str::@2 to printf_str::@1 [phi:printf_str/printf_str::@2->printf_str::@1]
__b1_from_printf_str:
__b1_from___b2:
// [12] phi (byte*) screen#10 = (byte*) screen#23 [phi:printf_str/printf_str::@2->printf_str::@1#0] -- register_copy
// [12] phi (byte*) printf_str::str#4 = (byte*) printf_str::str#6 [phi:printf_str/printf_str::@2->printf_str::@1#1] -- register_copy
jmp __b1
// printf_str::@1
__b1:
// [13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2 -- vbuc1_neq__deref_pbuz1_then_la1
ldy #0
lda (str),y
cmp #0
bne __b2
jmp __breturn
// printf_str::@return
__breturn:
// [14] return
rts
// printf_str::@2
__b2:
// [15] *((byte*) screen#10) ← *((byte*) printf_str::str#4) -- _deref_pbuz1=_deref_pbuz2
ldy #0
lda (str),y
ldy #0
sta (screen),y
// [16] (byte*) screen#1 ← ++ (byte*) screen#10 -- pbuz1=_inc_pbuz1
inc.z screen
bne !+
inc.z screen+1
!:
// [17] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#4 -- pbuz1=_inc_pbuz1
inc.z str
bne !+
inc.z str+1
!:
jmp __b1_from___b2
}
// printf_string
// Print a string value using a specific format
// Handles justification and min length
printf_string: {
// [19] call printf_str
// [11] phi from printf_string to printf_str [phi:printf_string->printf_str]
printf_str_from_printf_string:
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:printf_string->printf_str#0] -- register_copy
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::name [phi:printf_string->printf_str#1] -- pbuz1=pbuc1
lda #<main.name
sta.z printf_str.str
lda #>main.name
sta.z printf_str.str+1
jsr printf_str
jmp __breturn
// printf_string::@return
__breturn:
// [20] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2 [ screen#10 printf_str::str#4 ] ( main:2::printf_str:5 [ screen#10 printf_str::str#4 ] { } main:2::printf_str:9 [ screen#10 printf_str::str#4 ] { { screen#10 = screen#23 } } main:2::printf_string:7::printf_str:19 [ screen#10 printf_str::str#4 ] { { screen#10 = screen#23 } } ) always clobbers reg byte a reg byte y
Statement [15] *((byte*) screen#10) ← *((byte*) printf_str::str#4) [ screen#10 printf_str::str#4 ] ( main:2::printf_str:5 [ screen#10 printf_str::str#4 ] { } main:2::printf_str:9 [ screen#10 printf_str::str#4 ] { { screen#10 = screen#23 } } main:2::printf_string:7::printf_str:19 [ screen#10 printf_str::str#4 ] { { screen#10 = screen#23 } } ) always clobbers reg byte a reg byte y
Potential registers zp[2]:2 [ screen#23 screen#10 screen#1 ] : zp[2]:2 ,
Potential registers zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ] : zp[2]:4 ,
REGISTER UPLIFT SCOPES
Uplift Scope [printf_str] 31,254.25: zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
Uplift Scope [] 13,942.73: zp[2]:2 [ screen#23 screen#10 screen#1 ]
Uplift Scope [printf_format_string]
Uplift Scope [printf_string]
Uplift Scope [main]
Uplifting [printf_str] best 721 combination zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
Uplifting [] best 721 combination zp[2]:2 [ screen#23 screen#10 screen#1 ]
Uplifting [printf_format_string] best 721 combination
Uplifting [printf_string] best 721 combination
Uplifting [main] best 721 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Tests printf function call rewriting
// A simple string - with the printf-sub cuntions in the same file.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label screen = 2
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [5] call printf_str
// [11] phi from main to printf_str [phi:main->printf_str]
printf_str_from_main:
// [11] phi (byte*) screen#23 = (byte*) 1024 [phi:main->printf_str#0] -- pbuz1=pbuc1
lda #<$400
sta.z screen
lda #>$400
sta.z screen+1
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str [phi:main->printf_str#1] -- pbuz1=pbuc1
lda #<str
sta.z printf_str.str
lda #>str
sta.z printf_str.str+1
jsr printf_str
// [6] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
jmp __b1
// main::@1
__b1:
// [7] call printf_string
// [18] phi from main::@1 to printf_string [phi:main::@1->printf_string]
printf_string_from___b1:
jsr printf_string
// [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
__b2_from___b1:
jmp __b2
// main::@2
__b2:
// [9] call printf_str
// [11] phi from main::@2 to printf_str [phi:main::@2->printf_str]
printf_str_from___b2:
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:main::@2->printf_str#0] -- register_copy
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str1 [phi:main::@2->printf_str#1] -- pbuz1=pbuc1
lda #<str1
sta.z printf_str.str
lda #>str1
sta.z printf_str.str+1
jsr printf_str
jmp __breturn
// main::@return
__breturn:
// [10] return
rts
name: .text "Jesper"
.byte 0
str: .text "Hello, I am "
.byte 0
str1: .text ". who are you?"
.byte 0
}
// printf_str
// printf_str(byte* zp(4) str)
printf_str: {
.label str = 4
// [12] phi from printf_str printf_str::@2 to printf_str::@1 [phi:printf_str/printf_str::@2->printf_str::@1]
__b1_from_printf_str:
__b1_from___b2:
// [12] phi (byte*) screen#10 = (byte*) screen#23 [phi:printf_str/printf_str::@2->printf_str::@1#0] -- register_copy
// [12] phi (byte*) printf_str::str#4 = (byte*) printf_str::str#6 [phi:printf_str/printf_str::@2->printf_str::@1#1] -- register_copy
jmp __b1
// printf_str::@1
__b1:
// [13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2 -- vbuc1_neq__deref_pbuz1_then_la1
ldy #0
lda (str),y
cmp #0
bne __b2
jmp __breturn
// printf_str::@return
__breturn:
// [14] return
rts
// printf_str::@2
__b2:
// [15] *((byte*) screen#10) ← *((byte*) printf_str::str#4) -- _deref_pbuz1=_deref_pbuz2
ldy #0
lda (str),y
ldy #0
sta (screen),y
// [16] (byte*) screen#1 ← ++ (byte*) screen#10 -- pbuz1=_inc_pbuz1
inc.z screen
bne !+
inc.z screen+1
!:
// [17] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#4 -- pbuz1=_inc_pbuz1
inc.z str
bne !+
inc.z str+1
!:
jmp __b1_from___b2
}
// printf_string
// Print a string value using a specific format
// Handles justification and min length
printf_string: {
// [19] call printf_str
// [11] phi from printf_string to printf_str [phi:printf_string->printf_str]
printf_str_from_printf_string:
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:printf_string->printf_str#0] -- register_copy
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::name [phi:printf_string->printf_str#1] -- pbuz1=pbuc1
lda #<main.name
sta.z printf_str.str
lda #>main.name
sta.z printf_str.str+1
jsr printf_str
jmp __breturn
// printf_string::@return
__breturn:
// [20] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __b1
Removing instruction jmp __b2
Removing instruction jmp __breturn
Removing instruction jmp __b1
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction ldy #0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Replacing label __b1_from___b2 with __b1
Removing instruction __b1_from___bbegin:
Removing instruction __b1:
Removing instruction main_from___b1:
Removing instruction __bend_from___b1:
Removing instruction __b1_from_main:
Removing instruction printf_string_from___b1:
Removing instruction __b2_from___b1:
Removing instruction printf_str_from___b2:
Removing instruction __b1_from_printf_str:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __bend:
Removing instruction printf_str_from_main:
Removing instruction __b1:
Removing instruction __b2:
Removing instruction __breturn:
Removing instruction __breturn:
Removing instruction printf_str_from_printf_string:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction __bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(const byte*) main::name[] = (byte*) "Jesper"
(const byte*) main::str[(byte) $d] = (byte*) "Hello, I am "
(const byte*) main::str1[(byte) $f] = (byte*) ". who are you?"
(byte) printf_format_string::justify_left
(byte) printf_format_string::min_length
(void()) printf_str((byte*) printf_str::str)
(label) printf_str::@1
(label) printf_str::@2
(label) printf_str::@return
(byte*) printf_str::str
(byte*) printf_str::str#0 str zp[2]:4 20002.0
(byte*) printf_str::str#4 str zp[2]:4 10251.25
(byte*) printf_str::str#6 str zp[2]:4 1001.0
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
(label) printf_string::@return
(struct printf_format_string) printf_string::format
(byte) printf_string::format_justify_left
(byte) printf_string::format_min_length
(byte*) printf_string::str
(byte*) screen
(byte*) screen#1 screen zp[2]:2 10001.0
(byte*) screen#10 screen zp[2]:2 2828.7272727272725
(byte*) screen#23 screen zp[2]:2 1113.0
zp[2]:2 [ screen#23 screen#10 screen#1 ]
zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
FINAL ASSEMBLER
Score: 617
// File Comments
// Tests printf function call rewriting
// A simple string - with the printf-sub cuntions in the same file.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label screen = 2
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// printf("Hello, I am %s. who are you?", name)
// [5] call printf_str
// [11] phi from main to printf_str [phi:main->printf_str]
// [11] phi (byte*) screen#23 = (byte*) 1024 [phi:main->printf_str#0] -- pbuz1=pbuc1
lda #<$400
sta.z screen
lda #>$400
sta.z screen+1
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str [phi:main->printf_str#1] -- pbuz1=pbuc1
lda #<str
sta.z printf_str.str
lda #>str
sta.z printf_str.str+1
jsr printf_str
// [6] phi from main to main::@1 [phi:main->main::@1]
// main::@1
// printf("Hello, I am %s. who are you?", name)
// [7] call printf_string
// [18] phi from main::@1 to printf_string [phi:main::@1->printf_string]
jsr printf_string
// [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
// main::@2
// printf("Hello, I am %s. who are you?", name)
// [9] call printf_str
// [11] phi from main::@2 to printf_str [phi:main::@2->printf_str]
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:main::@2->printf_str#0] -- register_copy
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str1 [phi:main::@2->printf_str#1] -- pbuz1=pbuc1
lda #<str1
sta.z printf_str.str
lda #>str1
sta.z printf_str.str+1
jsr printf_str
// main::@return
// }
// [10] return
rts
name: .text "Jesper"
.byte 0
str: .text "Hello, I am "
.byte 0
str1: .text ". who are you?"
.byte 0
}
// printf_str
// printf_str(byte* zp(4) str)
printf_str: {
.label str = 4
// [12] phi from printf_str printf_str::@2 to printf_str::@1 [phi:printf_str/printf_str::@2->printf_str::@1]
// [12] phi (byte*) screen#10 = (byte*) screen#23 [phi:printf_str/printf_str::@2->printf_str::@1#0] -- register_copy
// [12] phi (byte*) printf_str::str#4 = (byte*) printf_str::str#6 [phi:printf_str/printf_str::@2->printf_str::@1#1] -- register_copy
// printf_str::@1
__b1:
// while(*str)
// [13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2 -- vbuc1_neq__deref_pbuz1_then_la1
ldy #0
lda (str),y
cmp #0
bne __b2
// printf_str::@return
// }
// [14] return
rts
// printf_str::@2
__b2:
// *screen++ = *str++
// [15] *((byte*) screen#10) ← *((byte*) printf_str::str#4) -- _deref_pbuz1=_deref_pbuz2
ldy #0
lda (str),y
sta (screen),y
// *screen++ = *str++;
// [16] (byte*) screen#1 ← ++ (byte*) screen#10 -- pbuz1=_inc_pbuz1
inc.z screen
bne !+
inc.z screen+1
!:
// [17] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#4 -- pbuz1=_inc_pbuz1
inc.z str
bne !+
inc.z str+1
!:
jmp __b1
}
// printf_string
// Print a string value using a specific format
// Handles justification and min length
printf_string: {
// printf_str(str)
// [19] call printf_str
// [11] phi from printf_string to printf_str [phi:printf_string->printf_str]
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:printf_string->printf_str#0] -- register_copy
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::name [phi:printf_string->printf_str#1] -- pbuz1=pbuc1
lda #<main.name
sta.z printf_str.str
lda #>main.name
sta.z printf_str.str+1
jsr printf_str
// printf_string::@return
// }
// [20] return
rts
}
// File Data

View File

@ -0,0 +1,33 @@
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(const byte*) main::name[] = (byte*) "Jesper"
(const byte*) main::str[(byte) $d] = (byte*) "Hello, I am "
(const byte*) main::str1[(byte) $f] = (byte*) ". who are you?"
(byte) printf_format_string::justify_left
(byte) printf_format_string::min_length
(void()) printf_str((byte*) printf_str::str)
(label) printf_str::@1
(label) printf_str::@2
(label) printf_str::@return
(byte*) printf_str::str
(byte*) printf_str::str#0 str zp[2]:4 20002.0
(byte*) printf_str::str#4 str zp[2]:4 10251.25
(byte*) printf_str::str#6 str zp[2]:4 1001.0
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
(label) printf_string::@return
(struct printf_format_string) printf_string::format
(byte) printf_string::format_justify_left
(byte) printf_string::format_min_length
(byte*) printf_string::str
(byte*) screen
(byte*) screen#1 screen zp[2]:2 10001.0
(byte*) screen#10 screen zp[2]:2 2828.7272727272725
(byte*) screen#23 screen zp[2]:2 1113.0
zp[2]:2 [ screen#23 screen#10 screen#1 ]
zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]

View File

@ -0,0 +1,12 @@
{
"folders": [
{
"path": "../kc"
}
],
"settings": {
"files.associations": {
"print.h": "c"
}
}
}