1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-23 13:31:12 +00:00

The first small test of calling convention VAR is working. TODO: return values, live ranges, allow registers for parameter/return transfer, entry points.

This commit is contained in:
jespergravgaard 2020-11-22 22:29:48 +01:00
parent 6cc6242a54
commit 2479fc08db
12 changed files with 903 additions and 698 deletions

View File

@ -310,7 +310,11 @@ public class Compiler {
}
new Pass1CallVoidReturns(program).execute();
new Pass1CallStackVar(program).execute();
//getLog().append("PROCEDURE CALLS");
//getLog().append(program.getGraph().toString(program));
new Pass1CallStack(program).execute();
new Pass1CallVar(program).execute();
new Pass1CallPhiParameters(program).execute();
//getLog().append("PROCEDURE PARAMETERS");
//getLog().append(program.getGraph().toString(program));

View File

@ -151,7 +151,7 @@ public class ControlFlowGraph implements Serializable {
public List<ControlFlowBlock> getEntryPointBlocks(Program program) {
List<ControlFlowBlock> entryPointBlocks = new ArrayList<>();
for(Procedure procedure : program.getScope().getAllProcedures(true)) {
if(ProcedureUtils.isEntrypoint(procedure.getRef(), program) || Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
if(ProcedureUtils.isEntrypoint(procedure.getRef(), program) || Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention()) || Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
// Address-of is used on the procedure
Label procedureLabel = procedure.getLabel();
ControlFlowBlock procedureBlock = getBlock(procedureLabel.getRef());

View File

@ -40,10 +40,12 @@ public class Procedure extends Scope {
/** The method for passing parameters and return value to the procedure. */
public enum CallingConvention {
/** Parameters and return value handled through call PHI-transitions. */
/** Parameters and return value handled through PHI-transitions. */
PHI_CALL("__phicall"),
/** Parameters and return value over the stack. */
STACK_CALL("__stackcall");
STACK_CALL("__stackcall"),
/** Parameters and return value handled through variables. */
VAR_CALL("__varcall");
private final String name;

View File

@ -29,4 +29,8 @@ public class ParamValue implements RValue {
return "param("+parameter.toString(program)+")";
}
@Override
public String toString() {
return toString(null);
}
}

View File

@ -78,7 +78,7 @@ ADDRESS_MAINMEM: '__mem' ;
FORM_SSA: '__ssa' ;
FORM_MA: '__ma' ;
INTRINSIC: '__intrinsic' ;
CALLINGCONVENTION: '__stackcall' | '__phicall' ;
CALLINGCONVENTION: '__stackcall' | '__phicall' | '__varcall' ;
IF: 'if' ;
ELSE: 'else' ;
WHILE: 'while' ;

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ import dk.camelot64.kickc.passes.utils.SizeOfConstants;
import java.util.*;
/** Handle calling convention {@link Procedure.CallingConvention#STACK_CALL} by converting the making control flow graph and symbols calling convention specific. */
/** Handle calling convention {@link Procedure.CallingConvention#STACK_CALL} by converting parameter passing / return values to stack operations. */
public class Pass1CallStack extends Pass2SsaOptimization {
public Pass1CallStack(Program program) {
@ -53,41 +53,6 @@ public class Pass1CallStack extends Pass2SsaOptimization {
if(createStackBase)
CallingConventionStack.getStackBaseConstant(getScope());
// Set variables modified in STACK_CALL procedures to load/store
for(Procedure procedure : getScope().getAllProcedures(true)) {
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
Set<VariableRef> modifiedVars = getProgram().getProcedureModifiedVars().getModifiedVars(procedure.getRef());
for(VariableRef modifiedVar : modifiedVars) {
final Variable variable = getScope().getVariable(modifiedVar);
if(variable.isKindPhiMaster()) {
getLog().append("Converting PHI-variable modified inside __stackcall procedure "+procedure.getFullName()+"() to load/store "+variable.toString(getProgram()));
variable.setKind(Variable.Kind.LOAD_STORE);
}
}
}
}
// Transform STACK_CALL calls to call-prepare, call-execute, call-finalize
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
while(stmtIt.hasNext()) {
Statement statement = stmtIt.next();
if(statement instanceof StatementCall) {
StatementCall call = (StatementCall) statement;
ProcedureRef procedureRef = call.getProcedure();
Procedure procedure = getScope().getProcedure(procedureRef);
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
boolean hasPrepare = (call.getParameters().size() > 0) || !SymbolType.VOID.equals(procedure.getReturnType());
stmtIt.remove();
stmtIt.add(new StatementCallPrepare(procedureRef, call.getParameters(), call.getSource(), hasPrepare?call.getComments():Comment.NO_COMMENTS));
stmtIt.add(new StatementCallExecute(procedureRef, call.getSource(), hasPrepare?Comment.NO_COMMENTS:call.getComments()));
stmtIt.add(new StatementCallFinalize(call.getlValue(), procedureRef, call.getSource(), Comment.NO_COMMENTS));
getLog().append("Calling convention " + Procedure.CallingConvention.STACK_CALL + " adding prepare/execute/finalize for " + call.toString(getProgram(), false));
}
}
}
}
// Convert param(xxx) to stackidx(PARAM_X) = xxx
if(offsetConstants.size() > 0) {
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {

View File

@ -0,0 +1,65 @@
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.*;
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.ProcedureRef;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.ListIterator;
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 */
public class Pass1CallStackVar extends Pass2SsaOptimization {
public Pass1CallStackVar(Program program) {
super(program);
}
@Override
public boolean step() {
// Set variables modified in STACK_CALL/VAR_CALL procedures to load/store
for(Procedure procedure : getScope().getAllProcedures(true)) {
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention()) || Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
Set<VariableRef> modifiedVars = getProgram().getProcedureModifiedVars().getModifiedVars(procedure.getRef());
for(VariableRef modifiedVar : modifiedVars) {
final Variable variable = getScope().getVariable(modifiedVar);
if(variable.isKindPhiMaster()) {
getLog().append("Converting PHI-variable modified inside "+procedure.getCallingConvention().getName()+" procedure "+procedure.getFullName()+"() to load/store "+variable.toString(getProgram()));
variable.setKind(Variable.Kind.LOAD_STORE);
}
}
}
}
// Transform STACK_CALL/VAR_CALL calls to call-prepare, call-execute, call-finalize
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
while(stmtIt.hasNext()) {
Statement statement = stmtIt.next();
if(statement instanceof StatementCall) {
StatementCall call = (StatementCall) statement;
ProcedureRef procedureRef = call.getProcedure();
Procedure procedure = getScope().getProcedure(procedureRef);
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention()) || Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
boolean hasPrepare = (call.getParameters().size() > 0) || !SymbolType.VOID.equals(procedure.getReturnType());
stmtIt.remove();
stmtIt.add(new StatementCallPrepare(procedureRef, call.getParameters(), call.getSource(), hasPrepare?call.getComments():Comment.NO_COMMENTS));
stmtIt.add(new StatementCallExecute(procedureRef, call.getSource(), hasPrepare?Comment.NO_COMMENTS:call.getComments()));
stmtIt.add(new StatementCallFinalize(call.getlValue(), procedureRef, call.getSource(), Comment.NO_COMMENTS));
getLog().append("Calling convention " + procedure.getCallingConvention().getName() + " adding prepare/execute/finalize for " + call.toString(getProgram(), false));
}
}
}
}
return false;
}
}

View File

@ -0,0 +1,145 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.Comment;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeInference;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.ParamValue;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
/** Handle calling convention {@link Procedure.CallingConvention#VAR_CALL } by converting the making control flow graph and symbols calling convention specific. */
public class Pass1CallVar extends Pass2SsaOptimization {
public Pass1CallVar(Program program) {
super(program);
}
@Override
public boolean step() {
// Set all parameter/return variables in VAR_CALL procedures to LOAD/STORE
for(Procedure procedure : getScope().getAllProcedures(true)) {
if(Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
for(Variable parameter : procedure.getParameters()) {
parameter.setKind(Variable.Kind.LOAD_STORE);
getLog().append("Converting parameter in "+procedure.getCallingConvention().getName()+" procedure to load/store "+parameter.toString(getProgram()));
}
if(!SymbolType.VOID.equals(procedure.getReturnType())) {
Variable returnVar = procedure.getLocalVariable("return");
returnVar.setKind(Variable.Kind.LOAD_STORE);
getLog().append("Converting return in "+procedure.getCallingConvention().getName()+" procedure to load/store "+returnVar.toString(getProgram()));
}
}
}
// Convert param(xxx) to ??? = xxx
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {
if(programValue.get() instanceof ParamValue) {
// Convert ParamValues to calling-convention specific param-value
ParamValue paramValue = (ParamValue) programValue.get();
VariableRef parameterRef = paramValue.getParameter();
SymbolType parameterType = SymbolTypeInference.inferType(getScope(), paramValue.getParameter());
final Variable paramVar = getScope().getVariable(parameterRef);
final Scope blockScope = paramVar.getScope();
if(blockScope instanceof Procedure) {
Procedure procedure = (Procedure) blockScope;
if(Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
throw new InternalError(paramValue.toString());
//programValue.set(stackIdxValue);
//getLog().append("Calling convention " + Procedure.CallingConvention.STACK_CALL + " replacing " + paramValue.toString(getProgram()) + " with " + stackIdxValue.toString(getProgram()));
}
}
}
}
);
// Convert procedure return xxx to proc.return = xxx;
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
while(stmtIt.hasNext()) {
Statement statement = stmtIt.next();
if(statement instanceof StatementReturn) {
final Scope blockScope = getScope().getScope(block.getScope());
if(blockScope instanceof Procedure) {
Procedure procedure = (Procedure) blockScope;
final SymbolType returnType = procedure.getReturnType();
if(!SymbolType.VOID.equals(returnType) && Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
final RValue value = ((StatementReturn) statement).getValue();
//stmtIt.previous();
//generateStackReturnValues(value, returnType, returnOffsetConstant, statement.getSource(), statement.getComments(), stmtIt);
//stmtIt.next();
//((StatementReturn) statement).setValue(null);
throw new InternalError(statement.toString());
}
}
}
}
}
// Convert xxx = callfinalize to xxx = proc.return
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
while(stmtIt.hasNext()) {
Statement statement = stmtIt.next();
if(statement instanceof StatementCallFinalize) {
final StatementCallFinalize call = (StatementCallFinalize) statement;
Procedure procedure = getScope().getProcedure(call.getProcedure());
final SymbolType returnType = procedure.getReturnType();
if(Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
final StatementSource source = call.getSource();
final List<Comment> comments = call.getComments();
final LValue lValue = call.getlValue();
if(lValue!=null) {
Variable returnVar = procedure.getLocalVariable("return");
stmtIt.previous();
stmtIt.add(new StatementAssignment(lValue, returnVar.getRef(), call.isInitialAssignment(), source, comments));
stmtIt.next();
}
stmtIt.remove();
}
}
}
}
// Convert callprepare(xxx,yyy,) to proc.param = xxx, ...;
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
while(stmtIt.hasNext()) {
Statement statement = stmtIt.next();
if(statement instanceof StatementCallPrepare) {
final StatementCallPrepare call = (StatementCallPrepare) statement;
Procedure procedure = getScope().getProcedure(call.getProcedure());
if(Procedure.CallingConvention.VAR_CALL.equals(procedure.getCallingConvention())) {
stmtIt.previous();
final StatementSource source = call.getSource();
List<Comment> comments = call.getComments();
final List<Variable> parameterDefs = procedure.getParameters();
for(int i = 0; i < parameterDefs.size(); i++) {
final RValue parameterVal = call.getParameters().get(i);
final Variable parameterDef = parameterDefs.get(i);
stmtIt.add(new StatementAssignment(parameterDef.getVariableRef(), parameterVal, false, source, comments));
comments = Comment.NO_COMMENTS;
}
stmtIt.next();
stmtIt.remove();
}
}
}
}
return false;
}
}

View File

@ -48,6 +48,11 @@ public class TestPrograms {
// compileAndCompare("unknown-var-problem.c", log().verboseParse());
//}
@Test
public void testVarCall1() throws IOException, URISyntaxException {
compileAndCompare("varcall-1.c", log());
}
@Test
public void testConstVolatileProblem1() throws IOException, URISyntaxException {
compileAndCompare("const-volatile-problem.c");

12
src/test/kc/varcall-1.c Normal file
View File

@ -0,0 +1,12 @@
// Test __varcall calling convention
void main() {
setbg(0);
setbg(0x0b);
}
char * const BGCOL = 0xd021;
__varcall void setbg(char col) {
*BGCOL = col;
}