1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-02-07 20:31:32 +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 */
public class Procedure extends Scope {
/** The return type. {@link SymbolType#VOID} if the procedure does not return a value. */
private final SymbolType returnType;
/** 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. */
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);
this.returnType = returnType;
this.declaredInline = false;
this.interruptType = null;
this.comments = new ArrayList<>();
this.codeSegment = codeSegment;
this.callingConvension = callingConvension;
}
public CallingConvension getCallingConvension() {
return callingConvension;
}
public void setCallingConvension(CallingConvension callingConvension) {
this.callingConvension = callingConvension;
}
public String getCodeSegment() {
@ -165,6 +204,9 @@ public class Procedure extends Scope {
if(declaredInline) {
res.append("inline ");
}
if(!callingConvension.equals(CallingConvension.PHI_CALL)) {
res.append(getCallingConvension().getName()).append(" ");
}
if(interruptType != null) {
res.append("interrupt(" + interruptType + ")");
}

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -301,6 +301,18 @@ public class KickCParserBaseListener implements KickCParserListener {
* <p>The default implementation does nothing.</p>
*/
@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}
*
@ -409,6 +421,18 @@ public class KickCParserBaseListener implements KickCParserListener {
* <p>The default implementation does nothing.</p>
*/
@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}
*

View File

@ -181,6 +181,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@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}
*
@ -244,6 +251,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@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}
*

View File

@ -273,6 +273,18 @@ public interface KickCParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
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}
* labeled alternative in {@link KickCParser#directive}.
@ -381,6 +393,18 @@ public interface KickCParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
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}.
* @param ctx the parse tree

View File

@ -168,6 +168,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
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}
* labeled alternative in {@link KickCParser#directive}.
@ -231,6 +238,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
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}.
* @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.SourceLoader;
import dk.camelot64.kickc.asm.AsmClobber;
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.operators.*;
import dk.camelot64.kickc.model.statements.*;
@ -159,6 +158,18 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
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. */
String currentCodeSegment = Scope.SEGMENT_CODE_DEFAULT;
@ -183,7 +194,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
SymbolType type = declVarType;
List<Directive> directives = declVarDirectives;
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));
procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx)));
scopeStack.push(procedure);
@ -668,24 +679,24 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
lValue.setDeclaredExport(true);
} else if(directive instanceof DirectiveAlign) {
if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) {
lValue.setDeclaredAlignment(((DirectiveAlign) directive).getAlignment());
lValue.setDeclaredAlignment(((DirectiveAlign) directive).alignment);
} else {
throw new CompileError("Error! Cannot align variable that is not a string or an array " + lValue.toString(program), source);
}
} else if(directive instanceof DirectiveRegister) {
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)
Registers.Register register = Registers.getRegister(directiveRegister.getName());
Registers.Register register = Registers.getRegister(directiveRegister.name);
if(register == null) {
throw new CompileError("Error! Unknown register " + directiveRegister.getName(), source);
throw new CompileError("Error! Unknown register " + directiveRegister.name, source);
}
lValue.setDeclaredRegister(register);
} else if(directiveRegister.getAddress() != null) {
} else if(directiveRegister.address != null) {
// Allocate to specific address
Long address = ((DirectiveRegister) directive).address;
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());
lValue.setDeclaredRegister(register);
@ -720,10 +731,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
for(Directive directive : directives) {
if(directive instanceof DirectiveInline) {
procedure.setDeclaredInline(true);
} else if(directive instanceof DirectiveCallingConvention) {
procedure.setCallingConvension(((DirectiveCallingConvention) directive).callingConvension);
} else if(directive instanceof DirectiveInterrupt) {
procedure.setInterruptType(((DirectiveInterrupt) directive).interruptType);
} else if(directive instanceof DirectiveReserveZp) {
procedure.setReservedZps(((DirectiveReserveZp) directive).getReservedZp());
procedure.setReservedZps(((DirectiveReserveZp) directive).reservedZp);
} else {
throw new CompileError("Unsupported function directive " + directive, source);
}
@ -771,6 +784,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return new DirectiveInterrupt(type);
}
@Override
public Directive visitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) {
Procedure.CallingConvension callingConvension = Procedure.CallingConvension.getCallingConvension(ctx.getText());
return new DirectiveCallingConvention(callingConvension);
}
@Override
public Directive visitDirectiveAlign(KickCParser.DirectiveAlignContext ctx) {
Number alignment = NumberParser.parseLiteral(ctx.NUMBER().getText());
@ -2136,6 +2155,16 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
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. */
private static class DirectiveInline implements Directive {
}
@ -2165,9 +2194,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
this.alignment = alignment;
}
public int getAlignment() {
return alignment;
}
}
/** Variable register allocation. */
@ -2185,13 +2211,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
this.address = address;
}
public String getName() {
return name;
}
public Long getAddress() {
return address;
}
}
/** Reservation of zero-page addresses */
@ -2202,10 +2221,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
this.reservedZp = reservedZp;
}
public List<Integer> getReservedZp() {
return reservedZp;
}
}

View File

@ -12,7 +12,7 @@ import dk.camelot64.kickc.model.values.*;
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 {
private Program program;
@ -49,10 +49,16 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
@Override
public StatementCall visitCall(StatementCall origCall) {
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
// Generate parameter passing assignments
ProcedureRef procedureRef = origCall.getProcedure();
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<RValue> parameterValues = origCall.getParameters();
if(parameterDecls.size()!=parameterValues.size()) {
@ -120,6 +126,10 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
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);
// Add self-assignments for all variables modified in the procedure
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
for(VariableRef modifiedVar : modifiedVars) {

View File

@ -12,7 +12,7 @@ import java.util.ArrayList;
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 {
@ -33,6 +33,13 @@ public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor
// Generate return value assignment
ProcedureRef procedureRef = origCall.getProcedure();
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();
StatementCall copyCall = new StatementCall(null, procedureName, null, origCall.getSource(), origCall.getComments());
copyCall.setProcedure(procedureRef);
@ -106,6 +113,13 @@ public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor
@Override
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()));
return null;
}

View File

@ -35,6 +35,18 @@ public class 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
public void testStringPointerProblem() throws IOException, URISyntaxException {
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;
}