1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-08-08 13:25:12 +00:00

Added syntax for procedure calling conventions - and a pragma changing the current calling convention. Added two tests. Changed Pass1 procedure-stuff to only handle the PHI calling convention. #316

This commit is contained in:
jespergravgaard
2019-09-17 01:11:51 +02:00
parent 63dbe9bc5e
commit 95f97d842a
18 changed files with 1789 additions and 1502 deletions

View File

@@ -12,7 +12,6 @@ import java.util.List;
/** Symbol describing a procedure/function */ /** Symbol describing a procedure/function */
public class Procedure extends Scope { public class Procedure extends Scope {
/** The return type. {@link SymbolType#VOID} if the procedure does not return a value. */ /** The return type. {@link SymbolType#VOID} if the procedure does not return a value. */
private final SymbolType returnType; private final SymbolType returnType;
/** The names of the parameters of the procedure. */ /** The names of the parameters of the procedure. */
@@ -28,13 +27,53 @@ public class Procedure extends Scope {
/** The code segment to put the procedure into. */ /** The code segment to put the procedure into. */
private String codeSegment; private String codeSegment;
public Procedure(String name, SymbolType returnType, Scope parentScope, String codeSegment, String dataSegment) { /** The method for passing parameters and return value to the procedure. */
public enum CallingConvension {
/** Parameters and return value handled through call PHI-transitions. */
PHI_CALL("__phicall"),
/** Parameters and return value over the stack. */
STACK_CALL("__stackcall");
private String name;
CallingConvension(String name) {
this.name = name;
}
public String getName() {
return name;
}
/** Get a calling convention by name. */
public static CallingConvension getCallingConvension(String name) {
for(CallingConvension value : CallingConvension.values()) {
if(value.getName().equalsIgnoreCase(name)) {
return value;
}
}
return null;
}
}
/** The calling convention used for this procedure. */
private CallingConvension callingConvension;
public Procedure(String name, SymbolType returnType, Scope parentScope, String codeSegment, String dataSegment, CallingConvension callingConvension) {
super(name, parentScope, dataSegment); super(name, parentScope, dataSegment);
this.returnType = returnType; this.returnType = returnType;
this.declaredInline = false; this.declaredInline = false;
this.interruptType = null; this.interruptType = null;
this.comments = new ArrayList<>(); this.comments = new ArrayList<>();
this.codeSegment = codeSegment; this.codeSegment = codeSegment;
this.callingConvension = callingConvension;
}
public CallingConvension getCallingConvension() {
return callingConvension;
}
public void setCallingConvension(CallingConvension callingConvension) {
this.callingConvension = callingConvension;
} }
public String getCodeSegment() { public String getCodeSegment() {
@@ -165,6 +204,9 @@ public class Procedure extends Scope {
if(declaredInline) { if(declaredInline) {
res.append("inline "); res.append("inline ");
} }
if(!callingConvension.equals(CallingConvension.PHI_CALL)) {
res.append(getCallingConvension().getName()).append(" ");
}
if(interruptType != null) { if(interruptType != null) {
res.append("interrupt(" + interruptType + ")"); res.append("interrupt(" + interruptType + ")");
} }

View File

@@ -280,8 +280,8 @@ public abstract class Scope implements Symbol, Serializable {
return (BlockScope) getSymbol(name); return (BlockScope) getSymbol(name);
} }
public Procedure addProcedure(String name, SymbolType type, String codeSegment, String dataSegment) { public Procedure addProcedure(String name, SymbolType type, String codeSegment, String dataSegment, Procedure.CallingConvension callingConvension) {
return add(new Procedure(name, type, this, codeSegment, dataSegment)); return add(new Procedure(name, type, this, codeSegment, dataSegment, callingConvension));
} }
public Procedure getProcedure(String name) { public Procedure getProcedure(String name) {

View File

@@ -81,6 +81,8 @@ REGISTER: 'register' ;
INLINE: 'inline' ; INLINE: 'inline' ;
VOLATILE: 'volatile' ; VOLATILE: 'volatile' ;
INTERRUPT: 'interrupt' ; INTERRUPT: 'interrupt' ;
CALLING: 'calling';
CALLINGCONVENTION: '__stackcall' | '__phicall' ;
IF: 'if' ; IF: 'if' ;
ELSE: 'else' ; ELSE: 'else' ;
WHILE: 'while' ; WHILE: 'while' ;

File diff suppressed because it is too large Load Diff

View File

@@ -54,84 +54,86 @@ REGISTER=53
INLINE=54 INLINE=54
VOLATILE=55 VOLATILE=55
INTERRUPT=56 INTERRUPT=56
IF=57 CALLING=57
ELSE=58 CALLINGCONVENTION=58
WHILE=59 IF=59
DO=60 ELSE=60
FOR=61 WHILE=61
SWITCH=62 DO=62
RETURN=63 FOR=63
BREAK=64 SWITCH=64
CONTINUE=65 RETURN=65
ASM=66 BREAK=66
DEFAULT=67 CONTINUE=67
CASE=68 ASM=68
STRUCT=69 DEFAULT=69
ENUM=70 CASE=70
SIZEOF=71 STRUCT=71
TYPEID=72 ENUM=72
KICKASM=73 SIZEOF=73
RESOURCE=74 TYPEID=74
USES=75 KICKASM=75
CLOBBERS=76 RESOURCE=76
BYTES=77 USES=77
CYCLES=78 CLOBBERS=78
LOGIC_NOT=79 BYTES=79
SIGNEDNESS=80 CYCLES=80
SIMPLETYPE=81 LOGIC_NOT=81
BOOLEAN=82 SIGNEDNESS=82
KICKASM_BODY=83 SIMPLETYPE=83
STRING=84 BOOLEAN=84
CHAR=85 KICKASM_BODY=85
NUMBER=86 STRING=86
NUMFLOAT=87 CHAR=87
BINFLOAT=88 NUMBER=88
DECFLOAT=89 NUMFLOAT=89
HEXFLOAT=90 BINFLOAT=90
NUMINT=91 DECFLOAT=91
BININTEGER=92 HEXFLOAT=92
DECINTEGER=93 NUMINT=93
HEXINTEGER=94 BININTEGER=94
NAME=95 DECINTEGER=95
WS=96 HEXINTEGER=96
COMMENT_LINE=97 NAME=97
COMMENT_BLOCK=98 WS=98
ASM_BYTE=99 COMMENT_LINE=99
ASM_MNEMONIC=100 COMMENT_BLOCK=100
ASM_IMM=101 ASM_BYTE=101
ASM_COLON=102 ASM_MNEMONIC=102
ASM_COMMA=103 ASM_IMM=103
ASM_PAR_BEGIN=104 ASM_COLON=104
ASM_PAR_END=105 ASM_COMMA=105
ASM_BRACKET_BEGIN=106 ASM_PAR_BEGIN=106
ASM_BRACKET_END=107 ASM_PAR_END=107
ASM_DOT=108 ASM_BRACKET_BEGIN=108
ASM_SHIFT_LEFT=109 ASM_BRACKET_END=109
ASM_SHIFT_RIGHT=110 ASM_DOT=110
ASM_PLUS=111 ASM_SHIFT_LEFT=111
ASM_MINUS=112 ASM_SHIFT_RIGHT=112
ASM_LESS_THAN=113 ASM_PLUS=113
ASM_GREATER_THAN=114 ASM_MINUS=114
ASM_MULTIPLY=115 ASM_LESS_THAN=115
ASM_DIVIDE=116 ASM_GREATER_THAN=116
ASM_CURLY_BEGIN=117 ASM_MULTIPLY=117
ASM_CURLY_END=118 ASM_DIVIDE=118
ASM_NUMBER=119 ASM_CURLY_BEGIN=119
ASM_NUMFLOAT=120 ASM_CURLY_END=120
ASM_BINFLOAT=121 ASM_NUMBER=121
ASM_DECFLOAT=122 ASM_NUMFLOAT=122
ASM_HEXFLOAT=123 ASM_BINFLOAT=123
ASM_NUMINT=124 ASM_DECFLOAT=124
ASM_BININTEGER=125 ASM_HEXFLOAT=125
ASM_DECINTEGER=126 ASM_NUMINT=126
ASM_HEXINTEGER=127 ASM_BININTEGER=127
ASM_CHAR=128 ASM_DECINTEGER=128
ASM_MULTI_REL=129 ASM_HEXINTEGER=129
ASM_MULTI_NAME=130 ASM_CHAR=130
ASM_NAME=131 ASM_MULTI_REL=131
ASM_WS=132 ASM_MULTI_NAME=132
ASM_COMMENT_LINE=133 ASM_NAME=133
ASM_COMMENT_BLOCK=134 ASM_WS=134
ASM_COMMENT_LINE=135
ASM_COMMENT_BLOCK=136
';'=8 ';'=8
'..'=11 '..'=11
'?'=12 '?'=12
@@ -169,28 +171,29 @@ ASM_COMMENT_BLOCK=134
'inline'=54 'inline'=54
'volatile'=55 'volatile'=55
'interrupt'=56 'interrupt'=56
'if'=57 'calling'=57
'else'=58 'if'=59
'while'=59 'else'=60
'do'=60 'while'=61
'for'=61 'do'=62
'switch'=62 'for'=63
'return'=63 'switch'=64
'break'=64 'return'=65
'continue'=65 'break'=66
'asm'=66 'continue'=67
'default'=67 'asm'=68
'case'=68 'default'=69
'struct'=69 'case'=70
'enum'=70 'struct'=71
'sizeof'=71 'enum'=72
'typeid'=72 'sizeof'=73
'kickasm'=73 'typeid'=74
'resource'=74 'kickasm'=75
'uses'=75 'resource'=76
'clobbers'=76 'uses'=77
'bytes'=77 'clobbers'=78
'cycles'=78 'bytes'=79
'!'=79 'cycles'=80
'.byte'=99 '!'=81
'#'=101 '.byte'=101
'#'=103

View File

@@ -91,6 +91,7 @@ globalDirective
| (PRAGMA CODESEG) PAR_BEGIN NAME PAR_END #globalDirectiveCodeSeg | (PRAGMA CODESEG) PAR_BEGIN NAME PAR_END #globalDirectiveCodeSeg
| (PRAGMA DATASEG) PAR_BEGIN NAME PAR_END #globalDirectiveDataSeg | (PRAGMA DATASEG) PAR_BEGIN NAME PAR_END #globalDirectiveDataSeg
| (PRAGMA ENCODING) PAR_BEGIN NAME PAR_END #globalDirectiveEncoding | (PRAGMA ENCODING) PAR_BEGIN NAME PAR_END #globalDirectiveEncoding
| (PRAGMA CALLING) PAR_BEGIN CALLINGCONVENTION PAR_END #globalDirectiveCalling
; ;
directive directive
@@ -103,6 +104,7 @@ directive
| VOLATILE #directiveVolatile | VOLATILE #directiveVolatile
| INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt | INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt
| RESERVE PAR_BEGIN NUMBER ( COMMA NUMBER )* PAR_END #directiveReserveZp | RESERVE PAR_BEGIN NUMBER ( COMMA NUMBER )* PAR_END #directiveReserveZp
| CALLINGCONVENTION #directiveCallingConvention
; ;
stmtSeq stmtSeq

File diff suppressed because it is too large Load Diff

View File

@@ -54,84 +54,86 @@ REGISTER=53
INLINE=54 INLINE=54
VOLATILE=55 VOLATILE=55
INTERRUPT=56 INTERRUPT=56
IF=57 CALLING=57
ELSE=58 CALLINGCONVENTION=58
WHILE=59 IF=59
DO=60 ELSE=60
FOR=61 WHILE=61
SWITCH=62 DO=62
RETURN=63 FOR=63
BREAK=64 SWITCH=64
CONTINUE=65 RETURN=65
ASM=66 BREAK=66
DEFAULT=67 CONTINUE=67
CASE=68 ASM=68
STRUCT=69 DEFAULT=69
ENUM=70 CASE=70
SIZEOF=71 STRUCT=71
TYPEID=72 ENUM=72
KICKASM=73 SIZEOF=73
RESOURCE=74 TYPEID=74
USES=75 KICKASM=75
CLOBBERS=76 RESOURCE=76
BYTES=77 USES=77
CYCLES=78 CLOBBERS=78
LOGIC_NOT=79 BYTES=79
SIGNEDNESS=80 CYCLES=80
SIMPLETYPE=81 LOGIC_NOT=81
BOOLEAN=82 SIGNEDNESS=82
KICKASM_BODY=83 SIMPLETYPE=83
STRING=84 BOOLEAN=84
CHAR=85 KICKASM_BODY=85
NUMBER=86 STRING=86
NUMFLOAT=87 CHAR=87
BINFLOAT=88 NUMBER=88
DECFLOAT=89 NUMFLOAT=89
HEXFLOAT=90 BINFLOAT=90
NUMINT=91 DECFLOAT=91
BININTEGER=92 HEXFLOAT=92
DECINTEGER=93 NUMINT=93
HEXINTEGER=94 BININTEGER=94
NAME=95 DECINTEGER=95
WS=96 HEXINTEGER=96
COMMENT_LINE=97 NAME=97
COMMENT_BLOCK=98 WS=98
ASM_BYTE=99 COMMENT_LINE=99
ASM_MNEMONIC=100 COMMENT_BLOCK=100
ASM_IMM=101 ASM_BYTE=101
ASM_COLON=102 ASM_MNEMONIC=102
ASM_COMMA=103 ASM_IMM=103
ASM_PAR_BEGIN=104 ASM_COLON=104
ASM_PAR_END=105 ASM_COMMA=105
ASM_BRACKET_BEGIN=106 ASM_PAR_BEGIN=106
ASM_BRACKET_END=107 ASM_PAR_END=107
ASM_DOT=108 ASM_BRACKET_BEGIN=108
ASM_SHIFT_LEFT=109 ASM_BRACKET_END=109
ASM_SHIFT_RIGHT=110 ASM_DOT=110
ASM_PLUS=111 ASM_SHIFT_LEFT=111
ASM_MINUS=112 ASM_SHIFT_RIGHT=112
ASM_LESS_THAN=113 ASM_PLUS=113
ASM_GREATER_THAN=114 ASM_MINUS=114
ASM_MULTIPLY=115 ASM_LESS_THAN=115
ASM_DIVIDE=116 ASM_GREATER_THAN=116
ASM_CURLY_BEGIN=117 ASM_MULTIPLY=117
ASM_CURLY_END=118 ASM_DIVIDE=118
ASM_NUMBER=119 ASM_CURLY_BEGIN=119
ASM_NUMFLOAT=120 ASM_CURLY_END=120
ASM_BINFLOAT=121 ASM_NUMBER=121
ASM_DECFLOAT=122 ASM_NUMFLOAT=122
ASM_HEXFLOAT=123 ASM_BINFLOAT=123
ASM_NUMINT=124 ASM_DECFLOAT=124
ASM_BININTEGER=125 ASM_HEXFLOAT=125
ASM_DECINTEGER=126 ASM_NUMINT=126
ASM_HEXINTEGER=127 ASM_BININTEGER=127
ASM_CHAR=128 ASM_DECINTEGER=128
ASM_MULTI_REL=129 ASM_HEXINTEGER=129
ASM_MULTI_NAME=130 ASM_CHAR=130
ASM_NAME=131 ASM_MULTI_REL=131
ASM_WS=132 ASM_MULTI_NAME=132
ASM_COMMENT_LINE=133 ASM_NAME=133
ASM_COMMENT_BLOCK=134 ASM_WS=134
ASM_COMMENT_LINE=135
ASM_COMMENT_BLOCK=136
';'=8 ';'=8
'..'=11 '..'=11
'?'=12 '?'=12
@@ -169,28 +171,29 @@ ASM_COMMENT_BLOCK=134
'inline'=54 'inline'=54
'volatile'=55 'volatile'=55
'interrupt'=56 'interrupt'=56
'if'=57 'calling'=57
'else'=58 'if'=59
'while'=59 'else'=60
'do'=60 'while'=61
'for'=61 'do'=62
'switch'=62 'for'=63
'return'=63 'switch'=64
'break'=64 'return'=65
'continue'=65 'break'=66
'asm'=66 'continue'=67
'default'=67 'asm'=68
'case'=68 'default'=69
'struct'=69 'case'=70
'enum'=70 'struct'=71
'sizeof'=71 'enum'=72
'typeid'=72 'sizeof'=73
'kickasm'=73 'typeid'=74
'resource'=74 'kickasm'=75
'uses'=75 'resource'=76
'clobbers'=76 'uses'=77
'bytes'=77 'clobbers'=78
'cycles'=78 'bytes'=79
'!'=79 'cycles'=80
'.byte'=99 '!'=81
'#'=101 '.byte'=101
'#'=103

View File

@@ -301,6 +301,18 @@ public class KickCParserBaseListener implements KickCParserListener {
* <p>The default implementation does nothing.</p> * <p>The default implementation does nothing.</p>
*/ */
@Override public void exitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx) { } @Override public void exitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx) { }
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
@@ -409,6 +421,18 @@ public class KickCParserBaseListener implements KickCParserListener {
* <p>The default implementation does nothing.</p> * <p>The default implementation does nothing.</p>
*/ */
@Override public void exitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx) { } @Override public void exitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) { }
/** /**
* {@inheritDoc} * {@inheritDoc}
* *

View File

@@ -181,6 +181,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p> * {@link #visitChildren} on {@code ctx}.</p>
*/ */
@Override public T visitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx) { return visitChildren(ctx); } @Override public T visitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx) { return visitChildren(ctx); }
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
@@ -244,6 +251,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p> * {@link #visitChildren} on {@code ctx}.</p>
*/ */
@Override public T visitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx) { return visitChildren(ctx); } @Override public T visitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) { return visitChildren(ctx); }
/** /**
* {@inheritDoc} * {@inheritDoc}
* *

View File

@@ -273,6 +273,18 @@ public interface KickCParserListener extends ParseTreeListener {
* @param ctx the parse tree * @param ctx the parse tree
*/ */
void exitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx); void exitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx);
/**
* Enter a parse tree produced by the {@code globalDirectiveCalling}
* labeled alternative in {@link KickCParser#globalDirective}.
* @param ctx the parse tree
*/
void enterGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx);
/**
* Exit a parse tree produced by the {@code globalDirectiveCalling}
* labeled alternative in {@link KickCParser#globalDirective}.
* @param ctx the parse tree
*/
void exitGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx);
/** /**
* Enter a parse tree produced by the {@code directiveConst} * Enter a parse tree produced by the {@code directiveConst}
* labeled alternative in {@link KickCParser#directive}. * labeled alternative in {@link KickCParser#directive}.
@@ -381,6 +393,18 @@ public interface KickCParserListener extends ParseTreeListener {
* @param ctx the parse tree * @param ctx the parse tree
*/ */
void exitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx); void exitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx);
/**
* Enter a parse tree produced by the {@code directiveCallingConvention}
* labeled alternative in {@link KickCParser#directive}.
* @param ctx the parse tree
*/
void enterDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx);
/**
* Exit a parse tree produced by the {@code directiveCallingConvention}
* labeled alternative in {@link KickCParser#directive}.
* @param ctx the parse tree
*/
void exitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx);
/** /**
* Enter a parse tree produced by {@link KickCParser#stmtSeq}. * Enter a parse tree produced by {@link KickCParser#stmtSeq}.
* @param ctx the parse tree * @param ctx the parse tree

View File

@@ -168,6 +168,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result * @return the visitor result
*/ */
T visitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx); T visitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx);
/**
* Visit a parse tree produced by the {@code globalDirectiveCalling}
* labeled alternative in {@link KickCParser#globalDirective}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx);
/** /**
* Visit a parse tree produced by the {@code directiveConst} * Visit a parse tree produced by the {@code directiveConst}
* labeled alternative in {@link KickCParser#directive}. * labeled alternative in {@link KickCParser#directive}.
@@ -231,6 +238,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result * @return the visitor result
*/ */
T visitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx); T visitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx);
/**
* Visit a parse tree produced by the {@code directiveCallingConvention}
* labeled alternative in {@link KickCParser#directive}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx);
/** /**
* Visit a parse tree produced by {@link KickCParser#stmtSeq}. * Visit a parse tree produced by {@link KickCParser#stmtSeq}.
* @param ctx the parse tree * @param ctx the parse tree

View File

@@ -3,7 +3,6 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.NumberParser; import dk.camelot64.kickc.NumberParser;
import dk.camelot64.kickc.SourceLoader; import dk.camelot64.kickc.SourceLoader;
import dk.camelot64.kickc.asm.AsmClobber; import dk.camelot64.kickc.asm.AsmClobber;
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.*; import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.operators.*; import dk.camelot64.kickc.model.operators.*;
import dk.camelot64.kickc.model.statements.*; import dk.camelot64.kickc.model.statements.*;
@@ -159,6 +158,18 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return null; return null;
} }
/** The current calling convention for procedures. */
Procedure.CallingConvension currentCallingConvention = Procedure.CallingConvension.PHI_CALL;
@Override
public Object visitGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx) {
Procedure.CallingConvension callingConvension = Procedure.CallingConvension.getCallingConvension(ctx.CALLINGCONVENTION().getText());
if(callingConvension!=null) {
currentCallingConvention = callingConvension;
}
return null;
}
/** The current code segment - if null the default segment is used. */ /** The current code segment - if null the default segment is used. */
String currentCodeSegment = Scope.SEGMENT_CODE_DEFAULT; String currentCodeSegment = Scope.SEGMENT_CODE_DEFAULT;
@@ -183,7 +194,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
SymbolType type = declVarType; SymbolType type = declVarType;
List<Directive> directives = declVarDirectives; List<Directive> directives = declVarDirectives;
String name = ctx.NAME().getText(); String name = ctx.NAME().getText();
Procedure procedure = getCurrentScope().addProcedure(name, type, currentCodeSegment, currentDataSegment); Procedure procedure = getCurrentScope().addProcedure(name, type, currentCodeSegment, currentDataSegment, currentCallingConvention);
addDirectives(procedure, directives, StatementSource.procedureBegin(ctx)); addDirectives(procedure, directives, StatementSource.procedureBegin(ctx));
procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx))); procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx)));
scopeStack.push(procedure); scopeStack.push(procedure);
@@ -668,24 +679,24 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
lValue.setDeclaredExport(true); lValue.setDeclaredExport(true);
} else if(directive instanceof DirectiveAlign) { } else if(directive instanceof DirectiveAlign) {
if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) { if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) {
lValue.setDeclaredAlignment(((DirectiveAlign) directive).getAlignment()); lValue.setDeclaredAlignment(((DirectiveAlign) directive).alignment);
} else { } else {
throw new CompileError("Error! Cannot align variable that is not a string or an array " + lValue.toString(program), source); throw new CompileError("Error! Cannot align variable that is not a string or an array " + lValue.toString(program), source);
} }
} else if(directive instanceof DirectiveRegister) { } else if(directive instanceof DirectiveRegister) {
DirectiveRegister directiveRegister = (DirectiveRegister) directive; DirectiveRegister directiveRegister = (DirectiveRegister) directive;
if(directiveRegister.getName() != null) { if(directiveRegister.name != null) {
// Ignore register directive without parameter (all variables are placed on ZP and attempted register uplift anyways) // Ignore register directive without parameter (all variables are placed on ZP and attempted register uplift anyways)
Registers.Register register = Registers.getRegister(directiveRegister.getName()); Registers.Register register = Registers.getRegister(directiveRegister.name);
if(register == null) { if(register == null) {
throw new CompileError("Error! Unknown register " + directiveRegister.getName(), source); throw new CompileError("Error! Unknown register " + directiveRegister.name, source);
} }
lValue.setDeclaredRegister(register); lValue.setDeclaredRegister(register);
} else if(directiveRegister.getAddress() != null) { } else if(directiveRegister.address != null) {
// Allocate to specific address // Allocate to specific address
Long address = ((DirectiveRegister) directive).address; Long address = ((DirectiveRegister) directive).address;
if(address>255) { if(address>255) {
throw new CompileError("Error! Register not on zeropage " + directiveRegister.getAddress(), source); throw new CompileError("Error! Register not on zeropage " + directiveRegister.address, source);
} }
Registers.Register register = new Registers.RegisterZpDeclared(address.intValue()); Registers.Register register = new Registers.RegisterZpDeclared(address.intValue());
lValue.setDeclaredRegister(register); lValue.setDeclaredRegister(register);
@@ -720,10 +731,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
for(Directive directive : directives) { for(Directive directive : directives) {
if(directive instanceof DirectiveInline) { if(directive instanceof DirectiveInline) {
procedure.setDeclaredInline(true); procedure.setDeclaredInline(true);
} else if(directive instanceof DirectiveCallingConvention) {
procedure.setCallingConvension(((DirectiveCallingConvention) directive).callingConvension);
} else if(directive instanceof DirectiveInterrupt) { } else if(directive instanceof DirectiveInterrupt) {
procedure.setInterruptType(((DirectiveInterrupt) directive).interruptType); procedure.setInterruptType(((DirectiveInterrupt) directive).interruptType);
} else if(directive instanceof DirectiveReserveZp) { } else if(directive instanceof DirectiveReserveZp) {
procedure.setReservedZps(((DirectiveReserveZp) directive).getReservedZp()); procedure.setReservedZps(((DirectiveReserveZp) directive).reservedZp);
} else { } else {
throw new CompileError("Unsupported function directive " + directive, source); throw new CompileError("Unsupported function directive " + directive, source);
} }
@@ -771,6 +784,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return new DirectiveInterrupt(type); return new DirectiveInterrupt(type);
} }
@Override
public Directive visitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) {
Procedure.CallingConvension callingConvension = Procedure.CallingConvension.getCallingConvension(ctx.getText());
return new DirectiveCallingConvention(callingConvension);
}
@Override @Override
public Directive visitDirectiveAlign(KickCParser.DirectiveAlignContext ctx) { public Directive visitDirectiveAlign(KickCParser.DirectiveAlignContext ctx) {
Number alignment = NumberParser.parseLiteral(ctx.NUMBER().getText()); Number alignment = NumberParser.parseLiteral(ctx.NUMBER().getText());
@@ -2136,6 +2155,16 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
private static class DirectiveConst implements Directive { private static class DirectiveConst implements Directive {
} }
/** Function with specific declared calling convention. */
private static class DirectiveCallingConvention implements Directive {
Procedure.CallingConvension callingConvension;
public DirectiveCallingConvention(Procedure.CallingConvension callingConvension) {
this.callingConvension = callingConvension;
}
}
/** Function declared inline. */ /** Function declared inline. */
private static class DirectiveInline implements Directive { private static class DirectiveInline implements Directive {
} }
@@ -2165,9 +2194,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
this.alignment = alignment; this.alignment = alignment;
} }
public int getAlignment() {
return alignment;
}
} }
/** Variable register allocation. */ /** Variable register allocation. */
@@ -2185,13 +2211,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
this.address = address; this.address = address;
} }
public String getName() {
return name;
}
public Long getAddress() {
return address;
}
} }
/** Reservation of zero-page addresses */ /** Reservation of zero-page addresses */
@@ -2202,10 +2221,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
this.reservedZp = reservedZp; this.reservedZp = reservedZp;
} }
public List<Integer> getReservedZp() {
return reservedZp;
}
} }

View File

@@ -12,7 +12,7 @@ import dk.camelot64.kickc.model.values.*;
import java.util.*; import java.util.*;
/** Pass that modifies a control flow graph to call procedures by passing parameters through registers */ /** Pass that modifies a control flow graph to call {@link dk.camelot64.kickc.model.symbols.Procedure.CallingConvension#PHI_CALL} procedures by passing parameters through registers */
public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor { public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
private Program program; private Program program;
@@ -49,10 +49,16 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
@Override @Override
public StatementCall visitCall(StatementCall origCall) { public StatementCall visitCall(StatementCall origCall) {
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
// Generate parameter passing assignments // Generate parameter passing assignments
ProcedureRef procedureRef = origCall.getProcedure(); ProcedureRef procedureRef = origCall.getProcedure();
Procedure procedure = getScope().getProcedure(procedureRef); Procedure procedure = getScope().getProcedure(procedureRef);
// If not PHI-call - skip
if(!Procedure.CallingConvension.PHI_CALL.equals(procedure.getCallingConvension())) {
StatementCall copyCall = super.visitCall(origCall);
copyCall.setProcedure(procedureRef);
return copyCall;
}
List<Variable> parameterDecls = procedure.getParameters(); List<Variable> parameterDecls = procedure.getParameters();
List<RValue> parameterValues = origCall.getParameters(); List<RValue> parameterValues = origCall.getParameters();
if(parameterDecls.size()!=parameterValues.size()) { if(parameterDecls.size()!=parameterValues.size()) {
@@ -120,6 +126,10 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
ControlFlowBlock currentBlock = getCurrentBlock(); ControlFlowBlock currentBlock = getCurrentBlock();
String currentProcName = currentBlock.getLabel().getScopeNames(); String currentProcName = currentBlock.getLabel().getScopeNames();
Procedure procedure = program.getScope().getProcedure(currentProcName); Procedure procedure = program.getScope().getProcedure(currentProcName);
// If not PHI-call - skip
if(!Procedure.CallingConvension.PHI_CALL.equals(procedure.getCallingConvension()))
return super.visitReturn(orig);
// Add self-assignments for all variables modified in the procedure // Add self-assignments for all variables modified in the procedure
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef()); Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
for(VariableRef modifiedVar : modifiedVars) { for(VariableRef modifiedVar : modifiedVars) {

View File

@@ -12,7 +12,7 @@ import java.util.ArrayList;
import java.util.Set; import java.util.Set;
/** /**
* Pass that modifies a control flow graph to call procedures by passing return value through registers * Pass that modifies a control flow graph to call procedures by passing return value through registers for {@link dk.camelot64.kickc.model.symbols.Procedure.CallingConvension#PHI_CALL}
*/ */
public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor { public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor {
@@ -33,6 +33,13 @@ public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor
// Generate return value assignment // Generate return value assignment
ProcedureRef procedureRef = origCall.getProcedure(); ProcedureRef procedureRef = origCall.getProcedure();
Procedure procedure = program.getScope().getProcedure(procedureRef); Procedure procedure = program.getScope().getProcedure(procedureRef);
// If not PHI-call - skip
if(!Procedure.CallingConvension.PHI_CALL.equals(procedure.getCallingConvension())) {
StatementCall copyCall = super.visitCall(origCall);
copyCall.setProcedure(procedureRef);
return copyCall;
}
String procedureName = origCall.getProcedureName(); String procedureName = origCall.getProcedureName();
StatementCall copyCall = new StatementCall(null, procedureName, null, origCall.getSource(), origCall.getComments()); StatementCall copyCall = new StatementCall(null, procedureName, null, origCall.getSource(), origCall.getComments());
copyCall.setProcedure(procedureRef); copyCall.setProcedure(procedureRef);
@@ -106,6 +113,13 @@ public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor
@Override @Override
public StatementReturn visitReturn(StatementReturn orig) { public StatementReturn visitReturn(StatementReturn orig) {
ControlFlowBlock currentBlock = getCurrentBlock();
String currentProcName = currentBlock.getLabel().getScopeNames();
Procedure procedure = program.getScope().getProcedure(currentProcName);
// If not PHI-call - skip
if(!Procedure.CallingConvension.PHI_CALL.equals(procedure.getCallingConvension()))
return super.visitReturn(orig);
addStatementToCurrentBlock(new StatementReturn(null, orig.getSource(), orig.getComments())); addStatementToCurrentBlock(new StatementReturn(null, orig.getSource(), orig.getComments()));
return null; return null;
} }

View File

@@ -35,6 +35,18 @@ public class TestPrograms {
public TestPrograms() { public TestPrograms() {
} }
/*
@Test
public void testProcedureCallingConventionStack1() throws IOException, URISyntaxException {
compileAndCompare("procedure-callingconvention-stack-1", log());
}
@Test
public void testProcedureCallingConventionStack0() throws IOException, URISyntaxException {
compileAndCompare("procedure-callingconvention-stack-0", log());
}
*/
@Test @Test
public void testStringPointerProblem() throws IOException, URISyntaxException { public void testStringPointerProblem() throws IOException, URISyntaxException {
compileAndCompare("string-pointer-problem"); compileAndCompare("string-pointer-problem");

View File

@@ -0,0 +1,11 @@
// Test a procedure with calling convention stack
const char* SCREEN = 0x0400;
void main(void) {
SCREEN[0] = plus('0', 7);
}
char __stackcall plus(char a, char b) {
return a+b;
}

View File

@@ -0,0 +1,13 @@
// Test a procedure with calling convention stack
const char* SCREEN = 0x0400;
void main(void) {
SCREEN[0] = plus('0', 7);
}
#pragma calling(__stackcall)
char plus(char a, char b) {
return a+b;
}