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:
parent
6cc6242a54
commit
2479fc08db
@ -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));
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
||||
|
@ -29,4 +29,8 @@ public class ParamValue implements RValue {
|
||||
return "param("+parameter.toString(program)+")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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) -> {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
145
src/main/java/dk/camelot64/kickc/passes/Pass1CallVar.java
Normal file
145
src/main/java/dk/camelot64/kickc/passes/Pass1CallVar.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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
12
src/test/kc/varcall-1.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user