1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-26 18:29:54 +00:00

Moved stack call parameter assignments out of pass 0. Added address-of handling for procedures converting them to stack call if they have parameters. #121

This commit is contained in:
jespergravgaard 2021-05-16 10:19:21 +02:00
parent 55e5e6bca2
commit f14dfe4252
25 changed files with 136 additions and 60 deletions

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.model.symbols;
import dk.camelot64.kickc.model.Comment;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.StatementSource;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
import dk.camelot64.kickc.model.values.ProcedureRef;
@ -38,6 +39,8 @@ public class Procedure extends Scope {
private final List<ProcedureRef> constructorRefs;
/** Is this procedure declared as a constructor procedure. */
private boolean isConstructor;
/** The source of the procedure definition. */
private StatementSource definitionSource;
/** The names of all legal intrinsic procedures. */
final public static List<String> INTRINSIC_PROCEDURES = Arrays.asList(
@ -93,6 +96,14 @@ public class Procedure extends Scope {
this.isConstructor = false;
}
public StatementSource getDefinitionSource() {
return definitionSource;
}
public void setDefinitionSource(StatementSource definitionSource) {
this.definitionSource = definitionSource;
}
public CallingConvention getCallingConvention() {
return callingConvention;
}

View File

@ -405,12 +405,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
// Add the body
addStatement(new StatementProcedureBegin(procedure.getRef(), StatementSource.procedureBegin(ctx), Comment.NO_COMMENTS));
// Add parameter assignments
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
for(Variable param : procedure.getParameters()) {
addStatement(new StatementAssignment((LValue) param.getRef(), new ParamValue((VariableRef) param.getRef()), true, StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
}
}
Label procExit = procedure.addLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
if(ctx.stmtSeq() != null) {
this.visit(ctx.stmtSeq());
@ -471,9 +466,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
}
if(defineProcedure) {
// Make sure comments and directives are from the definition
// Make sure comments, directives and source are from the definition
addDirectives(procedure, varDecl.getDeclDirectives(), statementSource);
procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx)));
procedure.setDefinitionSource(statementSource);
// enter the procedure
scopeStack.push(procedure);
// Add parameter variables...

View File

@ -5,13 +5,15 @@ import dk.camelot64.kickc.model.iterator.ProgramExpressionIterator;
import dk.camelot64.kickc.model.iterator.ProgramExpressionUnary;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Symbol;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
import dk.camelot64.kickc.model.values.ConstantSymbolPointer;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.SymbolVariableRef;
import dk.camelot64.kickc.model.values.SymbolRef;
import dk.camelot64.kickc.model.values.Value;
/**
@ -29,51 +31,56 @@ public class Pass1AddressOfHandling extends Pass2SsaOptimization {
ProgramExpressionIterator.execute(getProgram(), (programExpression, currentStmt, stmtIt, currentBlock) -> {
if(Operators.ADDRESS_OF.equals(programExpression.getOperator())) {
RValue rValue = ((ProgramExpressionUnary) programExpression).getOperand();
if(rValue instanceof SymbolVariableRef) {
Symbol toSymbol = getScope().getSymbol((SymbolVariableRef) rValue);
if(toSymbol instanceof Variable) {
final Variable variable = (Variable) toSymbol;
final String stmtStr = currentStmt.toString(getProgram(), false);
updateAddressOfVariable(variable, stmtStr);
}
}
updateAddressOfValue(rValue, currentStmt);
}
});
ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> {
if(programValue.get() instanceof ConstantSymbolPointer) {
// Values containing constant pointers
Value value = ((ConstantSymbolPointer) programValue.get()).getToSymbol();
if(value instanceof SymbolVariableRef) {
Symbol toSymbol = getScope().getSymbol((SymbolVariableRef) value);
if(toSymbol instanceof Variable) {
final Variable variable = (Variable) toSymbol;
if(!variable.isNoModify() && !variable.isVolatile()) {
final String stmtStr = currentStmt == null ? toSymbol.toString(getProgram()) : currentStmt.toString(getProgram(), false);
updateAddressOfVariable(variable, stmtStr);
}
}
}
updateAddressOfValue(value, currentStmt);
}
});
return false;
}
private void updateAddressOfVariable(Variable variable, String stmtStr) {
if(variable.getArraySpec()!=null)
return;
/**
* Modify variable/procedure affected by address-of
*
* @param value The value affected by address-of
* @param currentStmt The current statement
*/
private void updateAddressOfValue(Value value, Statement currentStmt) {
if(value instanceof SymbolRef) {
Symbol toSymbol = getScope().getSymbol((SymbolRef) value);
final String stmtStr = currentStmt == null ? toSymbol.toString(getProgram()) : currentStmt.toString(getProgram(), false);
if(toSymbol instanceof Variable) {
final Variable variable = (Variable) toSymbol;
if(!variable.isNoModify() && !variable.isVolatile()) {
if(variable.getArraySpec() != null)
return;
if(variable.getType() instanceof SymbolTypeStruct) {
variable.setKind(Variable.Kind.LOAD_STORE);
SymbolType typeQualified = variable.getType().getQualified(true, variable.getType().isNomodify());
variable.setType(typeQualified);
getLog().append("Setting struct to load/store in variable affected by address-of " + stmtStr);
//getLog().append("Setting struct to load/store in variable affected by address-of: " + variable.toString() + " in " + stmtStr);
} else {
variable.setKind(Variable.Kind.LOAD_STORE);
SymbolType typeQualified = variable.getType().getQualified(true, variable.getType().isNomodify());
variable.setType(typeQualified);
getLog().append("Setting inferred volatile on symbol affected by address-of " + stmtStr);
//getLog().append("Setting inferred volatile on symbol affected by address-of: " + variable.toString() + " in " + stmtStr);
if(variable.getType() instanceof SymbolTypeStruct) {
variable.setKind(Variable.Kind.LOAD_STORE);
SymbolType typeQualified = variable.getType().getQualified(true, variable.getType().isNomodify());
variable.setType(typeQualified);
getLog().append("Setting struct to load/store in variable affected by address-of " + stmtStr);
//getLog().append("Setting struct to load/store in variable affected by address-of: " + variable.toString() + " in " + stmtStr);
} else {
variable.setKind(Variable.Kind.LOAD_STORE);
SymbolType typeQualified = variable.getType().getQualified(true, variable.getType().isNomodify());
variable.setType(typeQualified);
getLog().append("Setting inferred volatile on symbol affected by address-of " + stmtStr);
//getLog().append("Setting inferred volatile on symbol affected by address-of: " + variable.toString() + " in " + stmtStr);
}
}
} else if(toSymbol instanceof Procedure) {
if(((Procedure) toSymbol).getParameters().size() > 0) {
((Procedure) toSymbol).setCallingConvention(Procedure.CallingConvention.STACK_CALL);
getLog().append("Setting inferred __stackcall on procedure affected by address-of " + toSymbol.toString(getProgram()) + " caused by statement " + stmtStr);
;
}
}
}
}

View File

@ -1,14 +1,21 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.Comment;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.ParamValue;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
/** Handle calling conventions {@link Procedure.CallingConvention#STACK_CALL} {@link Procedure.CallingConvention#VAR_CALL} by converting to call-prepare, call-execute, call-finalize */
/** Handle calling conventions {@link Procedure.CallingConvention#STACK_CALL} by converting parameters, return values and modified variables to load/store and by adding parameter assignemtn statements to procedures*/
public class Pass1CallStackVarPrepare extends Pass2SsaOptimization {
public Pass1CallStackVarPrepare(Program program) {
@ -47,6 +54,20 @@ public class Pass1CallStackVarPrepare extends Pass2SsaOptimization {
}
}
// Add parameter assignments at start of procedure in STACK_CALL procedures
for(Procedure procedure : getScope().getAllProcedures(true)) {
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
final ControlFlowBlock procedureBlock = getGraph().getBlock(procedure.getLabel().getRef());
final ArrayList<Variable> params = new ArrayList<>(procedure.getParameters());
Collections.reverse(params);
for(Variable param : params) {
final StatementAssignment paramAssignment = new StatementAssignment((LValue) param.getRef(), new ParamValue((VariableRef) param.getRef()), true, null, Comment.NO_COMMENTS);
procedureBlock.getStatements().add(0, paramAssignment);
getLog().append("Adding parameter assignment in "+procedure.getCallingConvention().getName()+" procedure "+paramAssignment.toString(getProgram(), false));
}
}
}
return false;
}

View File

@ -3020,6 +3020,11 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("function-pointer-param-workaround.c");
}
//@Test
//public void testFunctionPointerParam0() throws IOException {
// compileAndCompare("function-pointer-param-0.c", log().verboseParse().verboseCreateSsa());
//}
@Test
public void testFunctionPointerNoargCall14() throws IOException {
compileAndCompare("function-pointer-noarg-call-14.c");

View File

@ -0,0 +1,35 @@
// Test function pointers with parameters
// Currently the parameter is not transferred properly
void main() {
// A pointer to a function taking a single char param
void(*f)(char);
for(char i=0;i<160;i++) {
if((i&1)==0) {
fn3(i);
continue;
}
if((i&3)==1) {
f = &fn1;
} else {
f = &fn2;
}
(*f)(i);
}
}
char* const SCREEN = (char*)0x400;
void fn1(char c) {
SCREEN[c] = 'a';
}
void fn2(char d) {
SCREEN[d] = 'b';
}
__stackcall void fn3(char e) {
SCREEN[e] = 'c';
}

View File

@ -1,4 +1,6 @@
Loading link script "rom.ld"
Adding parameter assignment in __stackcall procedure call1::param2 = param(call1::param2)
Adding parameter assignment in __stackcall procedure call1::param1 = param(call1::param1)
Calling convention __stackcall adding prepare/execute/finalize for main::$0 = call call1 1 2
Calling convention __stackcall adding prepare/execute/finalize for main::$1 = call call1 3 4
Calling convention STACK_CALL replacing param(call1::param1) with stackidx(byte,call1::OFFSET_STACK_PARAM1)

View File

@ -16,7 +16,6 @@ plus: {
.const OFFSET_STACK_B = 0
.const OFFSET_STACK_RETURN = 1
.label a = 2
// }
tsx
lda STACK_BASE+OFFSET_STACK_A,x
sta.z a

View File

@ -1,3 +1,5 @@
Adding parameter assignment in __stackcall procedure plus::b = param(plus::b)
Adding parameter assignment in __stackcall procedure plus::a = param(plus::a)
Calling convention __stackcall adding prepare/execute/finalize for main::$0 = call plus '0' 7
Calling convention STACK_CALL replacing param(plus::a) with stackidx(byte,plus::OFFSET_STACK_A)
Calling convention STACK_CALL replacing param(plus::b) with stackidx(byte,plus::OFFSET_STACK_B)
@ -300,7 +302,6 @@ plus: {
.const OFFSET_STACK_B = 0
.const OFFSET_STACK_RETURN = 1
.label a = 2
// }
// [0] plus::a#0 = stackidx(byte,plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_A,x

View File

@ -16,7 +16,6 @@ plus: {
.const OFFSET_STACK_B = 0
.const OFFSET_STACK_RETURN = 1
.label a = 2
// }
tsx
lda STACK_BASE+OFFSET_STACK_A,x
sta.z a

View File

@ -1,3 +1,5 @@
Adding parameter assignment in __stackcall procedure plus::b = param(plus::b)
Adding parameter assignment in __stackcall procedure plus::a = param(plus::a)
Calling convention __stackcall adding prepare/execute/finalize for main::$0 = call plus '0' 7
Calling convention STACK_CALL replacing param(plus::a) with stackidx(byte,plus::OFFSET_STACK_A)
Calling convention STACK_CALL replacing param(plus::b) with stackidx(byte,plus::OFFSET_STACK_B)
@ -300,7 +302,6 @@ plus: {
.const OFFSET_STACK_B = 0
.const OFFSET_STACK_RETURN = 1
.label a = 2
// }
// [0] plus::a#0 = stackidx(byte,plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_A,x

View File

@ -24,7 +24,6 @@ __start: {
print: {
.const OFFSET_STACK_P_X = 1
.const OFFSET_STACK_P_Y = 0
// }
tsx
lda STACK_BASE+OFFSET_STACK_P_X,x
tay

View File

@ -1,4 +1,6 @@
Converting variable modified inside __stackcall procedure main() to load/store idx
Adding parameter assignment in __stackcall procedure get::i = param(get::i)
Adding parameter assignment in __stackcall procedure print::p = param(print::p)
Inlined call call __init
Eliminating unused variable with no statement main::$1
Calling convention __stackcall adding prepare/execute/finalize for { main::$1_x, main::$1_y } = call get main::i
@ -635,7 +637,6 @@ __start: {
print: {
.const OFFSET_STACK_P_X = 1
.const OFFSET_STACK_P_Y = 0
// }
// [5] print::p_x#0 = stackidx(byte,print::OFFSET_STACK_P_X) -- vbuyy=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_P_X,x

View File

@ -29,7 +29,6 @@ print: {
.const OFFSET_STACK_V_P2_Y = 0
.label v_p1_y = 4
.label v_p2_x = 5
// }
tsx
lda STACK_BASE+OFFSET_STACK_V_P1_X,x
tay

View File

@ -1,4 +1,6 @@
Converting variable modified inside __stackcall procedure main() to load/store idx
Adding parameter assignment in __stackcall procedure get::i = param(get::i)
Adding parameter assignment in __stackcall procedure print::v = param(print::v)
Inlined call call __init
Eliminating unused variable with no statement main::$1
Eliminating unused variable with no statement main::$1_p1
@ -941,7 +943,6 @@ print: {
.const OFFSET_STACK_V_P2_Y = 0
.label v_p1_y = 4
.label v_p2_x = 5
// }
// [5] print::v_p1_x#0 = stackidx(byte,print::OFFSET_STACK_V_P1_X) -- vbuyy=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_V_P1_X,x

View File

@ -25,7 +25,6 @@ print: {
.const OFFSET_STACK_SPACING = 0
.label str = 2
.label spacing = 5
// }
tsx
lda STACK_BASE+OFFSET_STACK_STR,x
sta.z str

View File

@ -1,4 +1,6 @@
Converting variable modified inside __stackcall procedure main() to load/store idx
Adding parameter assignment in __stackcall procedure print::spacing = param(print::spacing)
Adding parameter assignment in __stackcall procedure print::str = param(print::str)
Inlined call call __init
Calling convention __stackcall adding prepare/execute/finalize for call print main::str 1
Calling convention __stackcall adding prepare/execute/finalize for call print main::str1 2
@ -556,7 +558,6 @@ print: {
.const OFFSET_STACK_SPACING = 0
.label str = 2
.label spacing = 5
// }
// [5] print::str#0 = stackidx(byte*,print::OFFSET_STACK_STR) -- pbuz1=_stackidxptr_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_STR,x

View File

@ -15,7 +15,6 @@
pow2: {
.const OFFSET_STACK_N = 0
.const OFFSET_STACK_RETURN = 0
// }
tsx
lda STACK_BASE+OFFSET_STACK_N,x
// if (n == 0)

View File

@ -1,3 +1,4 @@
Adding parameter assignment in __stackcall procedure pow2::n = param(pow2::n)
Calling convention __stackcall adding prepare/execute/finalize for main::$0 = call pow2 6
Calling convention __stackcall adding prepare/execute/finalize for pow2::$2 = call pow2 pow2::$1
Calling convention STACK_CALL replacing param(pow2::n) with stackidx(byte,pow2::OFFSET_STACK_N)
@ -349,7 +350,6 @@ Score: 72
pow2: {
.const OFFSET_STACK_N = 0
.const OFFSET_STACK_RETURN = 0
// }
// [0] pow2::n#0 = stackidx(byte,pow2::OFFSET_STACK_N) -- vbuaa=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_N,x

View File

@ -18,7 +18,6 @@ plus: {
.label a = 4
.label b = 2
.label return = 4
// }
tsx
lda STACK_BASE+OFFSET_STACK_A,x
sta.z a

View File

@ -1,3 +1,5 @@
Adding parameter assignment in __stackcall procedure plus::b = param(plus::b)
Adding parameter assignment in __stackcall procedure plus::a = param(plus::a)
Calling convention __stackcall adding prepare/execute/finalize for main::$0 = call plus $1234 $2345
Calling convention STACK_CALL replacing param(plus::a) with stackidx(word,plus::OFFSET_STACK_A)
Calling convention STACK_CALL replacing param(plus::b) with stackidx(word,plus::OFFSET_STACK_B)
@ -338,7 +340,6 @@ plus: {
.label a = 4
.label b = 2
.label return = 4
// }
// [0] plus::a#0 = stackidx(word,plus::OFFSET_STACK_A) -- vwuz1=_stackidxword_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_A,x

View File

@ -21,7 +21,6 @@ plus: {
.label a = 4
.label b = 2
.label return = 4
// }
tsx
lda STACK_BASE+OFFSET_STACK_A,x
sta.z a

View File

@ -1,3 +1,5 @@
Adding parameter assignment in __stackcall procedure plus::b = param(plus::b)
Adding parameter assignment in __stackcall procedure plus::a = param(plus::a)
Calling convention __stackcall adding prepare/execute/finalize for main::$0 = call plus '0' 7
Calling convention STACK_CALL replacing param(plus::a) with stackidx(word,plus::OFFSET_STACK_A)
Calling convention STACK_CALL replacing param(plus::b) with stackidx(word,plus::OFFSET_STACK_B)
@ -340,7 +342,6 @@ plus: {
.label a = 4
.label b = 2
.label return = 4
// }
// [0] plus::a#0 = stackidx(word,plus::OFFSET_STACK_A) -- vwuz1=_stackidxword_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_A,x

View File

@ -25,7 +25,6 @@ plus: {
.const OFFSET_STACK_B = 0
.const OFFSET_STACK_RETURN = 1
.label a = 4
// }
tsx
lda STACK_BASE+OFFSET_STACK_A,x
sta.z a

View File

@ -1,4 +1,6 @@
Converting variable modified inside __stackcall procedure plus() to load/store i
Adding parameter assignment in __stackcall procedure plus::b = param(plus::b)
Adding parameter assignment in __stackcall procedure plus::a = param(plus::a)
Inlined call call __init
Calling convention __stackcall adding prepare/execute/finalize for main::$1 = call plus '0' main::v
Calling convention STACK_CALL replacing param(plus::a) with stackidx(byte,plus::OFFSET_STACK_A)
@ -517,7 +519,6 @@ plus: {
.const OFFSET_STACK_B = 0
.const OFFSET_STACK_RETURN = 1
.label a = 4
// }
// [5] plus::a#0 = stackidx(byte,plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_A,x